@ionic/core 7.4.3 → 7.4.4-dev.11696535998.1c8b00c5

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.
Files changed (61) hide show
  1. package/components/ion-content.js +51 -5
  2. package/components/ion-header.js +1 -1
  3. package/components/ion-nav.js +1 -1
  4. package/components/ion-router-outlet.js +4 -12
  5. package/components/ion-segment.js +35 -23
  6. package/components/ion-tab-bar.js +4 -0
  7. package/css/core.css +0 -1
  8. package/css/core.css.map +1 -1
  9. package/css/ionic.bundle.css +1 -1
  10. package/css/ionic.bundle.css.map +1 -1
  11. package/dist/cjs/ion-app_8.cjs.entry.js +54 -16
  12. package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
  13. package/dist/cjs/ion-segment_2.cjs.entry.js +35 -24
  14. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +4 -0
  15. package/dist/cjs/ionic.cjs.js +1 -1
  16. package/dist/cjs/loader.cjs.js +1 -1
  17. package/dist/collection/components/content/content.js +50 -10
  18. package/dist/collection/components/header/header.ios.css +25 -0
  19. package/dist/collection/components/nav/nav.css +0 -1
  20. package/dist/collection/components/router-outlet/router-outlet.css +0 -1
  21. package/dist/collection/components/router-outlet/router-outlet.js +3 -11
  22. package/dist/collection/components/segment/segment.js +35 -23
  23. package/dist/collection/components/segment/test/scrollable/segment.e2e.js +40 -1
  24. package/dist/collection/components/tab-bar/tab-bar.js +21 -0
  25. package/dist/collection/components/tab-bar/test/translucent/tab-bar.e2e.js +30 -0
  26. package/dist/docs.json +1 -7
  27. package/dist/esm/ion-app_8.entry.js +55 -17
  28. package/dist/esm/ion-nav_2.entry.js +1 -1
  29. package/dist/esm/ion-segment_2.entry.js +35 -24
  30. package/dist/esm/ion-tab-bar_2.entry.js +4 -0
  31. package/dist/esm/ionic.js +1 -1
  32. package/dist/esm/loader.js +1 -1
  33. package/dist/esm-es5/ion-app_8.entry.js +1 -1
  34. package/dist/esm-es5/ion-nav_2.entry.js +1 -1
  35. package/dist/esm-es5/ion-segment_2.entry.js +1 -1
  36. package/dist/esm-es5/ion-tab-bar_2.entry.js +1 -1
  37. package/dist/esm-es5/ionic.js +1 -1
  38. package/dist/esm-es5/loader.js +1 -1
  39. package/dist/ionic/ionic.esm.js +1 -1
  40. package/dist/ionic/p-6b3784a2.system.entry.js +4 -0
  41. package/dist/ionic/p-6d5c54f2.system.entry.js +4 -0
  42. package/dist/ionic/p-73eba881.system.js +1 -1
  43. package/dist/ionic/p-7b15d413.entry.js +4 -0
  44. package/dist/ionic/p-8f36cde3.system.entry.js +4 -0
  45. package/dist/ionic/p-b79eb3cd.entry.js +4 -0
  46. package/dist/ionic/p-c6f41736.entry.js +4 -0
  47. package/dist/ionic/p-e263255c.system.entry.js +4 -0
  48. package/dist/ionic/{p-1d67e7cb.entry.js → p-e7d69cad.entry.js} +1 -1
  49. package/dist/types/components/content/content.d.ts +2 -1
  50. package/dist/types/components/router-outlet/router-outlet.d.ts +1 -2
  51. package/dist/types/components/segment/segment.d.ts +1 -0
  52. package/dist/types/components/tab-bar/tab-bar.d.ts +8 -0
  53. package/hydrate/index.js +93 -41
  54. package/package.json +2 -2
  55. package/dist/ionic/p-26e8b917.system.entry.js +0 -4
  56. package/dist/ionic/p-414a1506.entry.js +0 -4
  57. package/dist/ionic/p-4603df44.system.entry.js +0 -4
  58. package/dist/ionic/p-50327060.entry.js +0 -4
  59. package/dist/ionic/p-8f245bb0.system.entry.js +0 -4
  60. package/dist/ionic/p-afafb6bf.system.entry.js +0 -4
  61. package/dist/ionic/p-c112f687.entry.js +0 -4
@@ -2,6 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { Host, h, writeTask } from "@stencil/core";
5
+ import { raf } from "../../utils/helpers";
5
6
  import { isRTL } from "../../utils/rtl/index";
6
7
  import { createColorClasses, hostContext } from "../../utils/theme";
7
8
  import { getIonMode } from "../../global/ionic-global";
@@ -78,29 +79,7 @@ export class Segment {
78
79
  * Used by `ion-segment-button` to determine if the button should be checked.
79
80
  */
80
81
  this.ionSelect.emit({ value });
81
- if (this.scrollable) {
82
- const buttons = this.getButtons();
83
- const activeButton = buttons.find((button) => button.value === value);
84
- if (activeButton !== undefined) {
85
- /**
86
- * Scrollable segment buttons should be
87
- * centered within the view including
88
- * buttons that are partially offscreen.
89
- */
90
- activeButton.scrollIntoView({
91
- behavior: 'smooth',
92
- inline: 'center',
93
- /**
94
- * Segment should scroll on the
95
- * horizontal axis. `block: 'nearest'`
96
- * ensures that the vertical axis
97
- * does not scroll if the segment
98
- * as a whole is already in view.
99
- */
100
- block: 'nearest',
101
- });
102
- }
103
- }
82
+ this.scrollActiveButtonIntoView();
104
83
  }
105
84
  disabledChanged() {
106
85
  this.gestureChanged();
@@ -122,6 +101,13 @@ export class Segment {
122
101
  }
123
102
  async componentDidLoad() {
124
103
  this.setCheckedClasses();
104
+ /**
105
+ * We need to wait for the buttons to all be rendered
106
+ * before we can scroll.
107
+ */
108
+ raf(() => {
109
+ this.scrollActiveButtonIntoView();
110
+ });
125
111
  this.gesture = (await import('../../utils/gesture')).createGesture({
126
112
  el: this.el,
127
113
  gestureName: 'segment',
@@ -250,6 +236,32 @@ export class Segment {
250
236
  buttons[next].classList.add('segment-button-after-checked');
251
237
  }
252
238
  }
239
+ scrollActiveButtonIntoView() {
240
+ const { scrollable, value } = this;
241
+ if (scrollable) {
242
+ const buttons = this.getButtons();
243
+ const activeButton = buttons.find((button) => button.value === value);
244
+ if (activeButton !== undefined) {
245
+ /**
246
+ * Scrollable segment buttons should be
247
+ * centered within the view including
248
+ * buttons that are partially offscreen.
249
+ */
250
+ activeButton.scrollIntoView({
251
+ behavior: 'smooth',
252
+ inline: 'center',
253
+ /**
254
+ * Segment should scroll on the
255
+ * horizontal axis. `block: 'nearest'`
256
+ * ensures that the vertical axis
257
+ * does not scroll if the segment
258
+ * as a whole is already in view.
259
+ */
260
+ block: 'nearest',
261
+ });
262
+ }
263
+ }
264
+ }
253
265
  setNextIndex(detail, isEnd = false) {
254
266
  const rtl = isRTL(this.el);
255
267
  const activated = this.activated;
@@ -4,7 +4,7 @@
4
4
  import { expect } from "@playwright/test";
5
5
  import { configs, test } from "../../../../utils/test/playwright/index";
6
6
  configs().forEach(({ title, screenshot, config }) => {
7
- test.describe(title('segment: scrollable'), () => {
7
+ test.describe(title('segment: scrollable (rendering)'), () => {
8
8
  test('should not have visual regressions', async ({ page }) => {
9
9
  await page.setContent(`
10
10
  <ion-segment scrollable="true" value="2">
@@ -42,3 +42,42 @@ configs().forEach(({ title, screenshot, config }) => {
42
42
  });
43
43
  });
44
44
  });
45
+ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
46
+ test.describe(title('segment: scrollable (functionality)'), () => {
47
+ test('should scroll active button into view when value is already set', async ({ page }) => {
48
+ await page.setContent(`
49
+ <ion-segment scrollable="true" value="8">
50
+ <ion-segment-button value="1">
51
+ <ion-label>First</ion-label>
52
+ </ion-segment-button>
53
+ <ion-segment-button value="2">
54
+ <ion-label>Second</ion-label>
55
+ </ion-segment-button>
56
+ <ion-segment-button value="3">
57
+ <ion-label>Third</ion-label>
58
+ </ion-segment-button>
59
+ <ion-segment-button value="4">
60
+ <ion-label>Fourth</ion-label>
61
+ </ion-segment-button>
62
+ <ion-segment-button value="5">
63
+ <ion-label>Fifth</ion-label>
64
+ </ion-segment-button>
65
+ <ion-segment-button value="6">
66
+ <ion-label>Sixth</ion-label>
67
+ </ion-segment-button>
68
+ <ion-segment-button value="7">
69
+ <ion-label>Seventh</ion-label>
70
+ </ion-segment-button>
71
+ <ion-segment-button id="activeButton" value="8">
72
+ <ion-label>Eighth</ion-label>
73
+ </ion-segment-button>
74
+ <ion-segment-button value="9">
75
+ <ion-label>Ninth</ion-label>
76
+ </ion-segment-button>
77
+ </ion-segment>
78
+ `, config);
79
+ const activeButton = page.locator('#activeButton');
80
+ await expect(activeButton).toBeInViewport();
81
+ });
82
+ });
83
+ });
@@ -44,6 +44,9 @@ export class TabBar {
44
44
  this.keyboardCtrl.destroy();
45
45
  }
46
46
  }
47
+ componentDidLoad() {
48
+ this.ionTabBarLoaded.emit();
49
+ }
47
50
  render() {
48
51
  const { color, translucent, keyboardVisible } = this;
49
52
  const mode = getIonMode(this);
@@ -160,6 +163,24 @@ export class TabBar {
160
163
  }
161
164
  }
162
165
  }
166
+ }, {
167
+ "method": "ionTabBarLoaded",
168
+ "name": "ionTabBarLoaded",
169
+ "bubbles": true,
170
+ "cancelable": true,
171
+ "composed": true,
172
+ "docs": {
173
+ "tags": [{
174
+ "name": "internal",
175
+ "text": "This event is used in IonContent to correctly\ncalculate the fullscreen content offsets\nwhen IonTabBar is used."
176
+ }],
177
+ "text": ""
178
+ },
179
+ "complexType": {
180
+ "original": "void",
181
+ "resolved": "void",
182
+ "references": {}
183
+ }
163
184
  }];
164
185
  }
165
186
  static get elementRef() { return "el"; }
@@ -36,5 +36,35 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, c
36
36
  const tabBar = page.locator('ion-tab-bar');
37
37
  await expect(tabBar).toHaveScreenshot(screenshot(`tab-bar-translucent`));
38
38
  });
39
+ test('should render translucent tab bar even when wrapped in a page container', async ({ page }) => {
40
+ await page.setContent(`
41
+ <style>
42
+ ion-content {
43
+ --background: linear-gradient(to right, orange, yellow, green, cyan, blue, violet);
44
+ }
45
+ </style>
46
+ <ion-tabs>
47
+ <div class="ion-page">
48
+ <ion-content fullscreen="true">My Content</ion-content>
49
+ </div>
50
+ <ion-tab-bar slot="bottom" translucent="true" selected-tab="1">
51
+ <ion-tab-button tab="1">
52
+ <ion-label>Recents</ion-label>
53
+ </ion-tab-button>
54
+
55
+ <ion-tab-button tab="2">
56
+ <ion-label>Favorites</ion-label>
57
+ <ion-badge>23</ion-badge>
58
+ </ion-tab-button>
59
+
60
+ <ion-tab-button tab="3">
61
+ <ion-label>Settings</ion-label>
62
+ </ion-tab-button>
63
+ </ion-tab-bar>
64
+ </ion-tabs>
65
+ `, config);
66
+ const tabBar = page.locator('ion-tab-bar');
67
+ await expect(tabBar).toHaveScreenshot(screenshot(`tab-bar-translucent-container`));
68
+ });
39
69
  });
40
70
  });
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2023-10-04T13:21:01",
2
+ "timestamp": "2023-10-05T20:02:12",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.4.0",
@@ -6714,12 +6714,6 @@
6714
6714
  }
6715
6715
  ],
6716
6716
  "listeners": [
6717
- {
6718
- "event": "appload",
6719
- "target": "window",
6720
- "capture": false,
6721
- "passive": false
6722
- },
6723
6717
  {
6724
6718
  "event": "resize",
6725
6719
  "target": "window",
@@ -3,13 +3,14 @@
3
3
  */
4
4
  import { r as registerInstance, h, H as Host, f as getElement, d as createEvent, e as readTask, i as forceUpdate, w as writeTask } from './index-cb894020.js';
5
5
  import { b as getIonMode, c as config, a as isPlatform } from './ionic-global-63a8d8c9.js';
6
- import { c as componentOnReady, l as clamp, i as inheritAriaAttributes, s as shallowEqualStringMap, m as hasLazyBuild } from './helpers-3379ba19.js';
6
+ import { m as hasLazyBuild, c as componentOnReady, l as clamp, i as inheritAriaAttributes, s as shallowEqualStringMap } from './helpers-3379ba19.js';
7
7
  import { i as isRTL } from './dir-912e3e13.js';
8
8
  import { c as createColorClasses, h as hostContext } from './theme-17531cdf.js';
9
9
  import { a as findIonContent, p as printIonContentErrorMsg, g as getScrollElement } from './index-746a238e.js';
10
10
  import { c as createKeyboardController } from './keyboard-controller-0c2dce71.js';
11
11
  import { g as getTimeGivenProgression } from './cubic-bezier-66542bc5.js';
12
12
  import { a as attachComponent, d as detachComponent } from './framework-delegate-aa433dea.js';
13
+ import { c as createLockController } from './lock-controller-e8c6c051.js';
13
14
  import { t as transition } from './index-32c6828b.js';
14
15
  import './index-595d62c9.js';
15
16
  import './index-7a14ecec.js';
@@ -146,6 +147,7 @@ const Content = class {
146
147
  this.cBottom = -1;
147
148
  this.isMainContent = true;
148
149
  this.resizeTimeout = null;
150
+ this.tabsElement = null;
149
151
  // Detail is used in a hot loop in the scroll event, by allocating it here
150
152
  // V8 will be able to inline any read/write to it since it's a monomorphic class.
151
153
  // https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html
@@ -176,12 +178,57 @@ const Content = class {
176
178
  }
177
179
  connectedCallback() {
178
180
  this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
181
+ /**
182
+ * The fullscreen content offsets need to be
183
+ * computed after the tab bar has loaded. Since
184
+ * lazy evaluation means components are not hydrated
185
+ * at the same time, we need to wait for the ionTabBarLoaded
186
+ * event to fire. This does not impact dist-custom-elements
187
+ * because there is no hydration there.
188
+ */
189
+ if (hasLazyBuild(this.el)) {
190
+ /**
191
+ * We need to cache the reference to the tabs.
192
+ * If just the content is unmounted then we won't
193
+ * be able to query for the closest tabs on disconnectedCallback
194
+ * since the content has been removed from the DOM tree.
195
+ */
196
+ const closestTabs = (this.tabsElement = this.el.closest('ion-tabs'));
197
+ if (closestTabs !== null) {
198
+ /**
199
+ * When adding and removing the event listener
200
+ * we need to make sure we pass the same function reference
201
+ * otherwise the event listener will not be removed properly.
202
+ * We can't only pass `this.resize` because "this" in the function
203
+ * context becomes a reference to IonTabs instead of IonContent.
204
+ *
205
+ * Additionally, we listen for ionTabBarLoaded on the IonTabs
206
+ * instance rather than the IonTabBar instance. It's possible for
207
+ * a tab bar to be conditionally rendered/mounted. Since ionTabBarLoaded
208
+ * bubbles, we can catch any instances of child tab bars loading by listening
209
+ * on IonTabs.
210
+ */
211
+ this.tabsLoadCallback = () => this.resize();
212
+ closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
213
+ }
214
+ }
179
215
  }
180
216
  disconnectedCallback() {
181
217
  this.onScrollEnd();
182
- }
183
- onAppLoad() {
184
- this.resize();
218
+ if (hasLazyBuild(this.el)) {
219
+ /**
220
+ * The event listener and tabs caches need to
221
+ * be cleared otherwise this will create a memory
222
+ * leak where the IonTabs instance can never be
223
+ * garbage collected.
224
+ */
225
+ const { tabsElement, tabsLoadCallback } = this;
226
+ if (tabsElement !== null && tabsLoadCallback !== undefined) {
227
+ tabsElement.removeEventListener('ionTabBarLoaded', tabsLoadCallback);
228
+ }
229
+ this.tabsElement = null;
230
+ this.tabsLoadCallback = undefined;
231
+ }
185
232
  }
186
233
  /**
187
234
  * Rotating certain devices can update
@@ -784,7 +831,7 @@ const handleHeaderFade = (scrollEl, baseEl, condenseHeader) => {
784
831
  });
785
832
  };
786
833
 
787
- const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:1px;z-index:1}.header-collapse-condense ion-toolbar{--background:var(--ion-background-color, #fff);z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{height:48px;padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}";
834
+ const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:1px;z-index:1}.header-collapse-condense ion-toolbar{--background:var(--ion-background-color, #fff);z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{height:48px;padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header:not(.header-collapse-main):has(~ion-content ion-header[collapse=condense]){opacity:0}";
788
835
 
789
836
  const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
790
837
 
@@ -935,7 +982,7 @@ Header.style = {
935
982
  md: headerMdCss
936
983
  };
937
984
 
938
- const routerOutletCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;overflow:hidden;z-index:0}";
985
+ const routerOutletCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;z-index:0}";
939
986
 
940
987
  const RouterOutlet = class {
941
988
  constructor(hostRef) {
@@ -943,6 +990,7 @@ const RouterOutlet = class {
943
990
  this.ionNavWillLoad = createEvent(this, "ionNavWillLoad", 7);
944
991
  this.ionNavWillChange = createEvent(this, "ionNavWillChange", 3);
945
992
  this.ionNavDidChange = createEvent(this, "ionNavDidChange", 3);
993
+ this.lockController = createLockController();
946
994
  this.gestureOrAnimationInProgress = false;
947
995
  this.mode = getIonMode(this);
948
996
  this.delegate = undefined;
@@ -1006,7 +1054,7 @@ const RouterOutlet = class {
1006
1054
  }
1007
1055
  /** @internal */
1008
1056
  async commit(enteringEl, leavingEl, opts) {
1009
- const unlock = await this.lock();
1057
+ const unlock = await this.lockController.lock();
1010
1058
  let changed = false;
1011
1059
  try {
1012
1060
  changed = await this.transition(enteringEl, leavingEl, opts);
@@ -1107,16 +1155,6 @@ const RouterOutlet = class {
1107
1155
  this.ionNavDidChange.emit();
1108
1156
  return true;
1109
1157
  }
1110
- // TODO: FW-5048 - Remove this code in favor of using lock controller from utils
1111
- async lock() {
1112
- const p = this.waitPromise;
1113
- let resolve;
1114
- this.waitPromise = new Promise((r) => (resolve = r));
1115
- if (p !== undefined) {
1116
- await p;
1117
- }
1118
- return resolve;
1119
- }
1120
1158
  render() {
1121
1159
  return h("slot", null);
1122
1160
  }
@@ -75,7 +75,7 @@ const convertToViews = (pages) => {
75
75
  .filter((v) => v !== null);
76
76
  };
77
77
 
78
- const navCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;overflow:hidden;z-index:0}";
78
+ const navCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;z-index:0}";
79
79
 
80
80
  const Nav = class {
81
81
  constructor(hostRef) {
@@ -2,10 +2,10 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { r as registerInstance, d as createEvent, w as writeTask, h, H as Host, f as getElement, i as forceUpdate } from './index-cb894020.js';
5
+ import { r as raf, a as addEventListener, b as removeEventListener, k as inheritAttributes } from './helpers-3379ba19.js';
5
6
  import { i as isRTL } from './dir-912e3e13.js';
6
7
  import { c as createColorClasses, h as hostContext } from './theme-17531cdf.js';
7
8
  import { b as getIonMode } from './ionic-global-63a8d8c9.js';
8
- import { a as addEventListener, b as removeEventListener, k as inheritAttributes } from './helpers-3379ba19.js';
9
9
 
10
10
  const segmentIosCss = ":host{--ripple-color:currentColor;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:grid;grid-auto-columns:1fr;position:relative;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:center;justify-content:center;width:100%;background:var(--background);font-family:var(--ion-font-family, inherit);text-align:center;contain:paint;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host(.segment-scrollable){-ms-flex-pack:start;justify-content:start;width:auto;overflow-x:auto;grid-auto-columns:minmax(-webkit-min-content, 1fr);grid-auto-columns:minmax(min-content, 1fr)}:host(.segment-scrollable::-webkit-scrollbar){display:none}:host{--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.065);border-radius:8px;overflow:hidden;z-index:0}:host(.ion-color){background:rgba(var(--ion-color-base-rgb), 0.065)}:host(.in-toolbar){-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;width:auto}:host(.in-toolbar:not(.ion-color)){background:var(--ion-toolbar-segment-background, var(--background))}:host(.in-toolbar-color:not(.ion-color)){background:rgba(var(--ion-color-contrast-rgb), 0.11)}";
11
11
 
@@ -85,29 +85,7 @@ const Segment = class {
85
85
  * Used by `ion-segment-button` to determine if the button should be checked.
86
86
  */
87
87
  this.ionSelect.emit({ value });
88
- if (this.scrollable) {
89
- const buttons = this.getButtons();
90
- const activeButton = buttons.find((button) => button.value === value);
91
- if (activeButton !== undefined) {
92
- /**
93
- * Scrollable segment buttons should be
94
- * centered within the view including
95
- * buttons that are partially offscreen.
96
- */
97
- activeButton.scrollIntoView({
98
- behavior: 'smooth',
99
- inline: 'center',
100
- /**
101
- * Segment should scroll on the
102
- * horizontal axis. `block: 'nearest'`
103
- * ensures that the vertical axis
104
- * does not scroll if the segment
105
- * as a whole is already in view.
106
- */
107
- block: 'nearest',
108
- });
109
- }
110
- }
88
+ this.scrollActiveButtonIntoView();
111
89
  }
112
90
  disabledChanged() {
113
91
  this.gestureChanged();
@@ -129,6 +107,13 @@ const Segment = class {
129
107
  }
130
108
  async componentDidLoad() {
131
109
  this.setCheckedClasses();
110
+ /**
111
+ * We need to wait for the buttons to all be rendered
112
+ * before we can scroll.
113
+ */
114
+ raf(() => {
115
+ this.scrollActiveButtonIntoView();
116
+ });
132
117
  this.gesture = (await import('./index-ff313b19.js')).createGesture({
133
118
  el: this.el,
134
119
  gestureName: 'segment',
@@ -257,6 +242,32 @@ const Segment = class {
257
242
  buttons[next].classList.add('segment-button-after-checked');
258
243
  }
259
244
  }
245
+ scrollActiveButtonIntoView() {
246
+ const { scrollable, value } = this;
247
+ if (scrollable) {
248
+ const buttons = this.getButtons();
249
+ const activeButton = buttons.find((button) => button.value === value);
250
+ if (activeButton !== undefined) {
251
+ /**
252
+ * Scrollable segment buttons should be
253
+ * centered within the view including
254
+ * buttons that are partially offscreen.
255
+ */
256
+ activeButton.scrollIntoView({
257
+ behavior: 'smooth',
258
+ inline: 'center',
259
+ /**
260
+ * Segment should scroll on the
261
+ * horizontal axis. `block: 'nearest'`
262
+ * ensures that the vertical axis
263
+ * does not scroll if the segment
264
+ * as a whole is already in view.
265
+ */
266
+ block: 'nearest',
267
+ });
268
+ }
269
+ }
270
+ }
260
271
  setNextIndex(detail, isEnd = false) {
261
272
  const rtl = isRTL(this.el);
262
273
  const activated = this.activated;
@@ -18,6 +18,7 @@ const TabBar = class {
18
18
  constructor(hostRef) {
19
19
  registerInstance(this, hostRef);
20
20
  this.ionTabBarChanged = createEvent(this, "ionTabBarChanged", 7);
21
+ this.ionTabBarLoaded = createEvent(this, "ionTabBarLoaded", 7);
21
22
  this.keyboardCtrl = null;
22
23
  this.keyboardVisible = false;
23
24
  this.color = undefined;
@@ -52,6 +53,9 @@ const TabBar = class {
52
53
  this.keyboardCtrl.destroy();
53
54
  }
54
55
  }
56
+ componentDidLoad() {
57
+ this.ionTabBarLoaded.emit();
58
+ }
55
59
  render() {
56
60
  const { color, translucent, keyboardVisible } = this;
57
61
  const mode = getIonMode(this);