@ionic/core 8.7.7-nightly.20251014 → 8.7.7-nightly.20251015

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 (36) hide show
  1. package/components/header.js +1 -1
  2. package/components/index2.js +74 -3
  3. package/dist/cjs/{index-CD5Rjp23.js → index-094mMFB-.js} +76 -5
  4. package/dist/cjs/index.cjs.js +3 -3
  5. package/dist/cjs/ion-app_8.cjs.entry.js +2 -2
  6. package/dist/cjs/ion-modal.cjs.entry.js +1 -1
  7. package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
  8. package/dist/cjs/ion-popover.cjs.entry.js +1 -1
  9. package/dist/cjs/{ios.transition-j9CclgEW.js → ios.transition-BOt_uW73.js} +1 -1
  10. package/dist/cjs/{md.transition-CwFyRSfv.js → md.transition-Dt968VXB.js} +1 -1
  11. package/dist/collection/components/header/header.ios.css +27 -1
  12. package/dist/collection/utils/transition/index.js +74 -3
  13. package/dist/docs.json +1 -1
  14. package/dist/esm/{index-D6G2seR8.js → index-r2D9DEro.js} +76 -5
  15. package/dist/esm/index.js +3 -3
  16. package/dist/esm/ion-app_8.entry.js +2 -2
  17. package/dist/esm/ion-modal.entry.js +1 -1
  18. package/dist/esm/ion-nav_2.entry.js +1 -1
  19. package/dist/esm/ion-popover.entry.js +1 -1
  20. package/dist/esm/{ios.transition-Bpq9ixwv.js → ios.transition-BDzw0_Hm.js} +1 -1
  21. package/dist/esm/{md.transition-zOA0oanq.js → md.transition-BzDYi3qq.js} +1 -1
  22. package/dist/ionic/index.esm.js +1 -1
  23. package/dist/ionic/ionic.esm.js +1 -1
  24. package/dist/ionic/p-7647da93.entry.js +4 -0
  25. package/dist/ionic/{p-DPhQmGJN.js → p-C7hRNDhM.js} +1 -1
  26. package/dist/ionic/p-DUt5fQmA.js +4 -0
  27. package/dist/ionic/{p-9R1XyICs.js → p-DZRJwG4S.js} +1 -1
  28. package/dist/ionic/{p-c59314fd.entry.js → p-a80f1b04.entry.js} +1 -1
  29. package/dist/ionic/{p-c85c40ee.entry.js → p-dbbe606a.entry.js} +1 -1
  30. package/dist/ionic/{p-de7b5fa3.entry.js → p-e16b69e1.entry.js} +1 -1
  31. package/dist/types/utils/transition/index.d.ts +9 -0
  32. package/hydrate/index.js +75 -4
  33. package/hydrate/index.mjs +75 -4
  34. package/package.json +1 -1
  35. package/dist/ionic/p-49f0149c.entry.js +0 -4
  36. package/dist/ionic/p-CMhMiYSX.js +0 -4
@@ -202,7 +202,7 @@ const handleHeaderFade = (scrollEl, baseEl, condenseHeader) => {
202
202
  });
203
203
  };
204
204
 
205
- 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:0px;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{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.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
205
+ 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-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.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:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{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 ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.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.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
206
206
 
207
207
  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}";
208
208
 
@@ -123,11 +123,22 @@ const iosTransitionAnimation = () => import('./ios.transition.js');
123
123
  const mdTransitionAnimation = () => import('./md.transition.js');
124
124
  const focusController = createFocusController();
125
125
  // TODO(FW-2832): types
126
+ /**
127
+ * Executes the main page transition.
128
+ * It also manages the lifecycle of header visibility (if any)
129
+ * to prevent visual flickering in iOS. The flickering only
130
+ * occurs for a condensed header that is placed above the content.
131
+ *
132
+ * @param opts Options for the transition.
133
+ * @returns A promise that resolves when the transition is complete.
134
+ */
126
135
  const transition = (opts) => {
127
136
  return new Promise((resolve, reject) => {
128
137
  writeTask(() => {
129
- beforeTransition(opts);
130
- runTransition(opts).then((result) => {
138
+ const transitioningInactiveHeader = getIosIonHeader(opts);
139
+ beforeTransition(opts, transitioningInactiveHeader);
140
+ runTransition(opts)
141
+ .then((result) => {
131
142
  if (result.animation) {
132
143
  result.animation.destroy();
133
144
  }
@@ -136,15 +147,21 @@ const transition = (opts) => {
136
147
  }, (error) => {
137
148
  afterTransition(opts);
138
149
  reject(error);
150
+ })
151
+ .finally(() => {
152
+ // Ensure that the header is restored to its original state.
153
+ setHeaderTransitionClass(transitioningInactiveHeader, false);
139
154
  });
140
155
  });
141
156
  });
142
157
  };
143
- const beforeTransition = (opts) => {
158
+ const beforeTransition = (opts, transitioningInactiveHeader) => {
144
159
  const enteringEl = opts.enteringEl;
145
160
  const leavingEl = opts.leavingEl;
146
161
  focusController.saveViewFocus(leavingEl);
147
162
  setZIndex(enteringEl, leavingEl, opts.direction);
163
+ // Prevent flickering of the header by adding a class.
164
+ setHeaderTransitionClass(transitioningInactiveHeader, true);
148
165
  if (opts.showGoBack) {
149
166
  enteringEl.classList.add('can-go-back');
150
167
  }
@@ -333,6 +350,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
333
350
  leavingEl.style.zIndex = '100';
334
351
  }
335
352
  };
353
+ /**
354
+ * Add a class to ensure that the header (if any)
355
+ * does not flicker during the transition. By adding the
356
+ * transitioning class, we ensure that the header has
357
+ * the necessary styles to prevent the following flickers:
358
+ * 1. When entering a page with a condensed header, the
359
+ * header should never be visible. However,
360
+ * it briefly renders the background color while
361
+ * the transition is occurring.
362
+ * 2. When leaving a page with a condensed header, the
363
+ * header has an opacity of 0 and the pages
364
+ * have a z-index which causes the entering page to
365
+ * briefly show it's content underneath the leaving page.
366
+ * 3. When entering a page or leaving a page with a fade
367
+ * header, the header should not have a background color.
368
+ * However, it briefly shows the background color while
369
+ * the transition is occurring.
370
+ *
371
+ * @param header The header element to modify.
372
+ * @param isTransitioning Whether the transition is occurring.
373
+ */
374
+ const setHeaderTransitionClass = (header, isTransitioning) => {
375
+ if (!header) {
376
+ return;
377
+ }
378
+ const transitionClass = 'header-transitioning';
379
+ if (isTransitioning) {
380
+ header.classList.add(transitionClass);
381
+ }
382
+ else {
383
+ header.classList.remove(transitionClass);
384
+ }
385
+ };
336
386
  const getIonPageElement = (element) => {
337
387
  if (element.classList.contains('ion-page')) {
338
388
  return element;
@@ -344,5 +394,26 @@ const getIonPageElement = (element) => {
344
394
  // idk, return the original element so at least something animates and we don't have a null pointer
345
395
  return element;
346
396
  };
397
+ /**
398
+ * Retrieves the ion-header element from a page based on the
399
+ * direction of the transition.
400
+ *
401
+ * @param opts Options for the transition.
402
+ * @returns The ion-header element or null if not found or not in 'ios' mode.
403
+ */
404
+ const getIosIonHeader = (opts) => {
405
+ const enteringEl = opts.enteringEl;
406
+ const leavingEl = opts.leavingEl;
407
+ const direction = opts.direction;
408
+ const mode = opts.mode;
409
+ if (mode !== 'ios') {
410
+ return null;
411
+ }
412
+ const element = direction === 'back' ? leavingEl : enteringEl;
413
+ if (!element) {
414
+ return null;
415
+ }
416
+ return element.querySelector('ion-header');
417
+ };
347
418
 
348
419
  export { LIFECYCLE_WILL_ENTER as L, LIFECYCLE_DID_ENTER as a, LIFECYCLE_WILL_LEAVE as b, LIFECYCLE_DID_LEAVE as c, LIFECYCLE_WILL_UNLOAD as d, deepReady as e, getIonPageElement as g, lifecycle as l, setPageHidden as s, transition as t, waitForMount as w };
@@ -120,15 +120,26 @@ const createFocusController = () => {
120
120
  };
121
121
  const LAST_FOCUS = 'ion-last-focus';
122
122
 
123
- const iosTransitionAnimation = () => Promise.resolve().then(function () { return require('./ios.transition-j9CclgEW.js'); });
124
- const mdTransitionAnimation = () => Promise.resolve().then(function () { return require('./md.transition-CwFyRSfv.js'); });
123
+ const iosTransitionAnimation = () => Promise.resolve().then(function () { return require('./ios.transition-BOt_uW73.js'); });
124
+ const mdTransitionAnimation = () => Promise.resolve().then(function () { return require('./md.transition-Dt968VXB.js'); });
125
125
  const focusController = createFocusController();
126
126
  // TODO(FW-2832): types
127
+ /**
128
+ * Executes the main page transition.
129
+ * It also manages the lifecycle of header visibility (if any)
130
+ * to prevent visual flickering in iOS. The flickering only
131
+ * occurs for a condensed header that is placed above the content.
132
+ *
133
+ * @param opts Options for the transition.
134
+ * @returns A promise that resolves when the transition is complete.
135
+ */
127
136
  const transition = (opts) => {
128
137
  return new Promise((resolve, reject) => {
129
138
  index.writeTask(() => {
130
- beforeTransition(opts);
131
- runTransition(opts).then((result) => {
139
+ const transitioningInactiveHeader = getIosIonHeader(opts);
140
+ beforeTransition(opts, transitioningInactiveHeader);
141
+ runTransition(opts)
142
+ .then((result) => {
132
143
  if (result.animation) {
133
144
  result.animation.destroy();
134
145
  }
@@ -137,15 +148,21 @@ const transition = (opts) => {
137
148
  }, (error) => {
138
149
  afterTransition(opts);
139
150
  reject(error);
151
+ })
152
+ .finally(() => {
153
+ // Ensure that the header is restored to its original state.
154
+ setHeaderTransitionClass(transitioningInactiveHeader, false);
140
155
  });
141
156
  });
142
157
  });
143
158
  };
144
- const beforeTransition = (opts) => {
159
+ const beforeTransition = (opts, transitioningInactiveHeader) => {
145
160
  const enteringEl = opts.enteringEl;
146
161
  const leavingEl = opts.leavingEl;
147
162
  focusController.saveViewFocus(leavingEl);
148
163
  setZIndex(enteringEl, leavingEl, opts.direction);
164
+ // Prevent flickering of the header by adding a class.
165
+ setHeaderTransitionClass(transitioningInactiveHeader, true);
149
166
  if (opts.showGoBack) {
150
167
  enteringEl.classList.add('can-go-back');
151
168
  }
@@ -334,6 +351,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
334
351
  leavingEl.style.zIndex = '100';
335
352
  }
336
353
  };
354
+ /**
355
+ * Add a class to ensure that the header (if any)
356
+ * does not flicker during the transition. By adding the
357
+ * transitioning class, we ensure that the header has
358
+ * the necessary styles to prevent the following flickers:
359
+ * 1. When entering a page with a condensed header, the
360
+ * header should never be visible. However,
361
+ * it briefly renders the background color while
362
+ * the transition is occurring.
363
+ * 2. When leaving a page with a condensed header, the
364
+ * header has an opacity of 0 and the pages
365
+ * have a z-index which causes the entering page to
366
+ * briefly show it's content underneath the leaving page.
367
+ * 3. When entering a page or leaving a page with a fade
368
+ * header, the header should not have a background color.
369
+ * However, it briefly shows the background color while
370
+ * the transition is occurring.
371
+ *
372
+ * @param header The header element to modify.
373
+ * @param isTransitioning Whether the transition is occurring.
374
+ */
375
+ const setHeaderTransitionClass = (header, isTransitioning) => {
376
+ if (!header) {
377
+ return;
378
+ }
379
+ const transitionClass = 'header-transitioning';
380
+ if (isTransitioning) {
381
+ header.classList.add(transitionClass);
382
+ }
383
+ else {
384
+ header.classList.remove(transitionClass);
385
+ }
386
+ };
337
387
  const getIonPageElement = (element) => {
338
388
  if (element.classList.contains('ion-page')) {
339
389
  return element;
@@ -345,6 +395,27 @@ const getIonPageElement = (element) => {
345
395
  // idk, return the original element so at least something animates and we don't have a null pointer
346
396
  return element;
347
397
  };
398
+ /**
399
+ * Retrieves the ion-header element from a page based on the
400
+ * direction of the transition.
401
+ *
402
+ * @param opts Options for the transition.
403
+ * @returns The ion-header element or null if not found or not in 'ios' mode.
404
+ */
405
+ const getIosIonHeader = (opts) => {
406
+ const enteringEl = opts.enteringEl;
407
+ const leavingEl = opts.leavingEl;
408
+ const direction = opts.direction;
409
+ const mode = opts.mode;
410
+ if (mode !== 'ios') {
411
+ return null;
412
+ }
413
+ const element = direction === 'back' ? leavingEl : enteringEl;
414
+ if (!element) {
415
+ return null;
416
+ }
417
+ return element.querySelector('ion-header');
418
+ };
348
419
 
349
420
  exports.LIFECYCLE_DID_ENTER = LIFECYCLE_DID_ENTER;
350
421
  exports.LIFECYCLE_DID_LEAVE = LIFECYCLE_DID_LEAVE;
@@ -4,9 +4,9 @@
4
4
  'use strict';
5
5
 
6
6
  var animation = require('./animation-Bt3H9L1C.js');
7
- var index = require('./index-CD5Rjp23.js');
8
- var ios_transition = require('./ios.transition-j9CclgEW.js');
9
- var md_transition = require('./md.transition-CwFyRSfv.js');
7
+ var index = require('./index-094mMFB-.js');
8
+ var ios_transition = require('./ios.transition-BOt_uW73.js');
9
+ var md_transition = require('./md.transition-Dt968VXB.js');
10
10
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
11
11
  var index$1 = require('./index-CAvQ7Tka.js');
12
12
  var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
@@ -14,7 +14,7 @@ var keyboardController = require('./keyboard-controller-GXBiBRKS.js');
14
14
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
15
15
  var frameworkDelegate = require('./framework-delegate-DMJRBuDi.js');
16
16
  var lockController = require('./lock-controller-aDB9wrEf.js');
17
- var index$2 = require('./index-CD5Rjp23.js');
17
+ var index$2 = require('./index-094mMFB-.js');
18
18
  require('./index-DkNv4J_i.js');
19
19
  require('./keyboard-UuAS4D_9.js');
20
20
  require('./capacitor-DmA66EwP.js');
@@ -904,7 +904,7 @@ const handleHeaderFade = (scrollEl, baseEl, condenseHeader) => {
904
904
  });
905
905
  };
906
906
 
907
- 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:0px;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{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.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
907
+ 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-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.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:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{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 ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.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.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
908
908
 
909
909
  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}";
910
910
 
@@ -11,7 +11,7 @@ var lockController = require('./lock-controller-aDB9wrEf.js');
11
11
  var capacitor = require('./capacitor-DmA66EwP.js');
12
12
  var overlays = require('./overlays-DxIZwUXI.js');
13
13
  var theme = require('./theme-CeDs6Hcv.js');
14
- var index$4 = require('./index-CD5Rjp23.js');
14
+ var index$4 = require('./index-094mMFB-.js');
15
15
  var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
16
16
  var keyboard = require('./keyboard-hHzlEQpk.js');
17
17
  var animation = require('./animation-Bt3H9L1C.js');
@@ -6,7 +6,7 @@
6
6
  var index = require('./index-D6Wc6v08.js');
7
7
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
8
8
  var helpers = require('./helpers-DrTqNghc.js');
9
- var index$1 = require('./index-CD5Rjp23.js');
9
+ var index$1 = require('./index-094mMFB-.js');
10
10
  var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
11
11
  var frameworkDelegate = require('./framework-delegate-DMJRBuDi.js');
12
12
 
@@ -10,7 +10,7 @@ var helpers = require('./helpers-DrTqNghc.js');
10
10
  var lockController = require('./lock-controller-aDB9wrEf.js');
11
11
  var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
12
12
  var theme = require('./theme-CeDs6Hcv.js');
13
- var index$1 = require('./index-CD5Rjp23.js');
13
+ var index$1 = require('./index-094mMFB-.js');
14
14
  var animation = require('./animation-Bt3H9L1C.js');
15
15
  require('./index-DkNv4J_i.js');
16
16
  require('./hardware-back-button-VCK4V3mG.js');
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var animation = require('./animation-Bt3H9L1C.js');
7
- var index = require('./index-CD5Rjp23.js');
7
+ var index = require('./index-094mMFB-.js');
8
8
  require('./index-D6Wc6v08.js');
9
9
  require('./index-DkNv4J_i.js');
10
10
  require('./helpers-DrTqNghc.js');
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var animation = require('./animation-Bt3H9L1C.js');
7
- var index = require('./index-CD5Rjp23.js');
7
+ var index = require('./index-094mMFB-.js');
8
8
  require('./index-D6Wc6v08.js');
9
9
  require('./index-DkNv4J_i.js');
10
10
  require('./helpers-DrTqNghc.js');
@@ -152,6 +152,15 @@ ion-header ion-toolbar:first-of-type {
152
152
  --opacity-scale: inherit;
153
153
  }
154
154
 
155
+ /**
156
+ * Override styles applied during the page transition to prevent
157
+ * header flickering.
158
+ */
159
+ .header-collapse-fade.header-transitioning ion-toolbar {
160
+ --background: transparent;
161
+ --border-style: none;
162
+ }
163
+
155
164
  .header-collapse-condense {
156
165
  z-index: 9;
157
166
  }
@@ -175,7 +184,6 @@ ion-header ion-toolbar:first-of-type {
175
184
  * since it needs to blend in with the header above it.
176
185
  */
177
186
  .header-collapse-condense ion-toolbar {
178
- --background: var(--ion-background-color, #fff);
179
187
  z-index: 0;
180
188
  }
181
189
 
@@ -201,6 +209,24 @@ ion-header ion-toolbar:first-of-type {
201
209
  transition: all 0.2s ease-in-out;
202
210
  }
203
211
 
212
+ /**
213
+ * Large title toolbar should just use the content background
214
+ * since it needs to blend in with the header above it.
215
+ */
216
+ .header-collapse-condense ion-toolbar,
217
+ .header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar {
218
+ --background: var(--ion-background-color, #fff);
219
+ }
220
+
221
+ /**
222
+ * Override styles applied during the page transition to prevent
223
+ * header flickering.
224
+ */
225
+ .header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar {
226
+ --border-style: none;
227
+ --opacity-scale: 1;
228
+ }
229
+
204
230
  .header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,
205
231
  .header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse {
206
232
  opacity: 0;
@@ -10,11 +10,22 @@ const iosTransitionAnimation = () => import('./ios.transition');
10
10
  const mdTransitionAnimation = () => import('./md.transition');
11
11
  const focusController = createFocusController();
12
12
  // TODO(FW-2832): types
13
+ /**
14
+ * Executes the main page transition.
15
+ * It also manages the lifecycle of header visibility (if any)
16
+ * to prevent visual flickering in iOS. The flickering only
17
+ * occurs for a condensed header that is placed above the content.
18
+ *
19
+ * @param opts Options for the transition.
20
+ * @returns A promise that resolves when the transition is complete.
21
+ */
13
22
  export const transition = (opts) => {
14
23
  return new Promise((resolve, reject) => {
15
24
  writeTask(() => {
16
- beforeTransition(opts);
17
- runTransition(opts).then((result) => {
25
+ const transitioningInactiveHeader = getIosIonHeader(opts);
26
+ beforeTransition(opts, transitioningInactiveHeader);
27
+ runTransition(opts)
28
+ .then((result) => {
18
29
  if (result.animation) {
19
30
  result.animation.destroy();
20
31
  }
@@ -23,15 +34,21 @@ export const transition = (opts) => {
23
34
  }, (error) => {
24
35
  afterTransition(opts);
25
36
  reject(error);
37
+ })
38
+ .finally(() => {
39
+ // Ensure that the header is restored to its original state.
40
+ setHeaderTransitionClass(transitioningInactiveHeader, false);
26
41
  });
27
42
  });
28
43
  });
29
44
  };
30
- const beforeTransition = (opts) => {
45
+ const beforeTransition = (opts, transitioningInactiveHeader) => {
31
46
  const enteringEl = opts.enteringEl;
32
47
  const leavingEl = opts.leavingEl;
33
48
  focusController.saveViewFocus(leavingEl);
34
49
  setZIndex(enteringEl, leavingEl, opts.direction);
50
+ // Prevent flickering of the header by adding a class.
51
+ setHeaderTransitionClass(transitioningInactiveHeader, true);
35
52
  if (opts.showGoBack) {
36
53
  enteringEl.classList.add('can-go-back');
37
54
  }
@@ -220,6 +237,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
220
237
  leavingEl.style.zIndex = '100';
221
238
  }
222
239
  };
240
+ /**
241
+ * Add a class to ensure that the header (if any)
242
+ * does not flicker during the transition. By adding the
243
+ * transitioning class, we ensure that the header has
244
+ * the necessary styles to prevent the following flickers:
245
+ * 1. When entering a page with a condensed header, the
246
+ * header should never be visible. However,
247
+ * it briefly renders the background color while
248
+ * the transition is occurring.
249
+ * 2. When leaving a page with a condensed header, the
250
+ * header has an opacity of 0 and the pages
251
+ * have a z-index which causes the entering page to
252
+ * briefly show it's content underneath the leaving page.
253
+ * 3. When entering a page or leaving a page with a fade
254
+ * header, the header should not have a background color.
255
+ * However, it briefly shows the background color while
256
+ * the transition is occurring.
257
+ *
258
+ * @param header The header element to modify.
259
+ * @param isTransitioning Whether the transition is occurring.
260
+ */
261
+ const setHeaderTransitionClass = (header, isTransitioning) => {
262
+ if (!header) {
263
+ return;
264
+ }
265
+ const transitionClass = 'header-transitioning';
266
+ if (isTransitioning) {
267
+ header.classList.add(transitionClass);
268
+ }
269
+ else {
270
+ header.classList.remove(transitionClass);
271
+ }
272
+ };
223
273
  export const getIonPageElement = (element) => {
224
274
  if (element.classList.contains('ion-page')) {
225
275
  return element;
@@ -231,3 +281,24 @@ export const getIonPageElement = (element) => {
231
281
  // idk, return the original element so at least something animates and we don't have a null pointer
232
282
  return element;
233
283
  };
284
+ /**
285
+ * Retrieves the ion-header element from a page based on the
286
+ * direction of the transition.
287
+ *
288
+ * @param opts Options for the transition.
289
+ * @returns The ion-header element or null if not found or not in 'ios' mode.
290
+ */
291
+ const getIosIonHeader = (opts) => {
292
+ const enteringEl = opts.enteringEl;
293
+ const leavingEl = opts.leavingEl;
294
+ const direction = opts.direction;
295
+ const mode = opts.mode;
296
+ if (mode !== 'ios') {
297
+ return null;
298
+ }
299
+ const element = direction === 'back' ? leavingEl : enteringEl;
300
+ if (!element) {
301
+ return null;
302
+ }
303
+ return element.querySelector('ion-header');
304
+ };
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2025-10-14T06:11:22",
2
+ "timestamp": "2025-10-15T06:11:13",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.38.0",
@@ -118,15 +118,26 @@ const createFocusController = () => {
118
118
  };
119
119
  const LAST_FOCUS = 'ion-last-focus';
120
120
 
121
- const iosTransitionAnimation = () => import('./ios.transition-Bpq9ixwv.js');
122
- const mdTransitionAnimation = () => import('./md.transition-zOA0oanq.js');
121
+ const iosTransitionAnimation = () => import('./ios.transition-BDzw0_Hm.js');
122
+ const mdTransitionAnimation = () => import('./md.transition-BzDYi3qq.js');
123
123
  const focusController = createFocusController();
124
124
  // TODO(FW-2832): types
125
+ /**
126
+ * Executes the main page transition.
127
+ * It also manages the lifecycle of header visibility (if any)
128
+ * to prevent visual flickering in iOS. The flickering only
129
+ * occurs for a condensed header that is placed above the content.
130
+ *
131
+ * @param opts Options for the transition.
132
+ * @returns A promise that resolves when the transition is complete.
133
+ */
125
134
  const transition = (opts) => {
126
135
  return new Promise((resolve, reject) => {
127
136
  writeTask(() => {
128
- beforeTransition(opts);
129
- runTransition(opts).then((result) => {
137
+ const transitioningInactiveHeader = getIosIonHeader(opts);
138
+ beforeTransition(opts, transitioningInactiveHeader);
139
+ runTransition(opts)
140
+ .then((result) => {
130
141
  if (result.animation) {
131
142
  result.animation.destroy();
132
143
  }
@@ -135,15 +146,21 @@ const transition = (opts) => {
135
146
  }, (error) => {
136
147
  afterTransition(opts);
137
148
  reject(error);
149
+ })
150
+ .finally(() => {
151
+ // Ensure that the header is restored to its original state.
152
+ setHeaderTransitionClass(transitioningInactiveHeader, false);
138
153
  });
139
154
  });
140
155
  });
141
156
  };
142
- const beforeTransition = (opts) => {
157
+ const beforeTransition = (opts, transitioningInactiveHeader) => {
143
158
  const enteringEl = opts.enteringEl;
144
159
  const leavingEl = opts.leavingEl;
145
160
  focusController.saveViewFocus(leavingEl);
146
161
  setZIndex(enteringEl, leavingEl, opts.direction);
162
+ // Prevent flickering of the header by adding a class.
163
+ setHeaderTransitionClass(transitioningInactiveHeader, true);
147
164
  if (opts.showGoBack) {
148
165
  enteringEl.classList.add('can-go-back');
149
166
  }
@@ -332,6 +349,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
332
349
  leavingEl.style.zIndex = '100';
333
350
  }
334
351
  };
352
+ /**
353
+ * Add a class to ensure that the header (if any)
354
+ * does not flicker during the transition. By adding the
355
+ * transitioning class, we ensure that the header has
356
+ * the necessary styles to prevent the following flickers:
357
+ * 1. When entering a page with a condensed header, the
358
+ * header should never be visible. However,
359
+ * it briefly renders the background color while
360
+ * the transition is occurring.
361
+ * 2. When leaving a page with a condensed header, the
362
+ * header has an opacity of 0 and the pages
363
+ * have a z-index which causes the entering page to
364
+ * briefly show it's content underneath the leaving page.
365
+ * 3. When entering a page or leaving a page with a fade
366
+ * header, the header should not have a background color.
367
+ * However, it briefly shows the background color while
368
+ * the transition is occurring.
369
+ *
370
+ * @param header The header element to modify.
371
+ * @param isTransitioning Whether the transition is occurring.
372
+ */
373
+ const setHeaderTransitionClass = (header, isTransitioning) => {
374
+ if (!header) {
375
+ return;
376
+ }
377
+ const transitionClass = 'header-transitioning';
378
+ if (isTransitioning) {
379
+ header.classList.add(transitionClass);
380
+ }
381
+ else {
382
+ header.classList.remove(transitionClass);
383
+ }
384
+ };
335
385
  const getIonPageElement = (element) => {
336
386
  if (element.classList.contains('ion-page')) {
337
387
  return element;
@@ -343,5 +393,26 @@ const getIonPageElement = (element) => {
343
393
  // idk, return the original element so at least something animates and we don't have a null pointer
344
394
  return element;
345
395
  };
396
+ /**
397
+ * Retrieves the ion-header element from a page based on the
398
+ * direction of the transition.
399
+ *
400
+ * @param opts Options for the transition.
401
+ * @returns The ion-header element or null if not found or not in 'ios' mode.
402
+ */
403
+ const getIosIonHeader = (opts) => {
404
+ const enteringEl = opts.enteringEl;
405
+ const leavingEl = opts.leavingEl;
406
+ const direction = opts.direction;
407
+ const mode = opts.mode;
408
+ if (mode !== 'ios') {
409
+ return null;
410
+ }
411
+ const element = direction === 'back' ? leavingEl : enteringEl;
412
+ if (!element) {
413
+ return null;
414
+ }
415
+ return element.querySelector('ion-header');
416
+ };
346
417
 
347
418
  export { LIFECYCLE_WILL_ENTER as L, LIFECYCLE_DID_ENTER as a, LIFECYCLE_WILL_LEAVE as b, LIFECYCLE_DID_LEAVE as c, LIFECYCLE_WILL_UNLOAD as d, deepReady as e, getIonPageElement as g, lifecycle as l, setPageHidden as s, transition as t, waitForMount as w };
package/dist/esm/index.js CHANGED
@@ -2,9 +2,9 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  export { c as createAnimation } from './animation-Dt8bGnA-.js';
5
- export { a as LIFECYCLE_DID_ENTER, c as LIFECYCLE_DID_LEAVE, L as LIFECYCLE_WILL_ENTER, b as LIFECYCLE_WILL_LEAVE, d as LIFECYCLE_WILL_UNLOAD, g as getIonPageElement } from './index-D6G2seR8.js';
6
- export { iosTransitionAnimation } from './ios.transition-Bpq9ixwv.js';
7
- export { mdTransitionAnimation } from './md.transition-zOA0oanq.js';
5
+ export { a as LIFECYCLE_DID_ENTER, c as LIFECYCLE_DID_LEAVE, L as LIFECYCLE_WILL_ENTER, b as LIFECYCLE_WILL_LEAVE, d as LIFECYCLE_WILL_UNLOAD, g as getIonPageElement } from './index-r2D9DEro.js';
6
+ export { iosTransitionAnimation } from './ios.transition-BDzw0_Hm.js';
7
+ export { mdTransitionAnimation } from './md.transition-BzDYi3qq.js';
8
8
  export { g as getTimeGivenProgression } from './cubic-bezier-hHmYLOfE.js';
9
9
  export { createGesture } from './index-CfgBF1SE.js';
10
10
  export { g as getPlatforms, i as initialize, a as isPlatform } from './ionic-global-CDrldh-5.js';