@ionic/core 8.7.3-dev.11755600455.1e79c35a → 8.7.3-dev.11755696506.17b8097b
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/components/ion-refresher.js +18 -1
- package/components/overlays.js +102 -2
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/ion-action-sheet.cjs.entry.js +1 -1
- package/dist/cjs/ion-alert.cjs.entry.js +1 -1
- package/dist/cjs/ion-datetime_3.cjs.entry.js +1 -1
- package/dist/cjs/ion-loading.cjs.entry.js +1 -1
- package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
- package/dist/cjs/ion-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-popover.cjs.entry.js +1 -1
- package/dist/cjs/ion-refresher_2.cjs.entry.js +18 -1
- package/dist/cjs/ion-select-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
- package/dist/cjs/ion-toast.cjs.entry.js +1 -1
- package/dist/cjs/{overlays-DUsEBICv.js → overlays-DFkeeMZX.js} +101 -1
- package/dist/collection/components/refresher/refresher.js +18 -1
- package/dist/collection/utils/overlays.js +102 -1
- package/dist/docs.json +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/ion-action-sheet.entry.js +1 -1
- package/dist/esm/ion-alert.entry.js +1 -1
- package/dist/esm/ion-datetime_3.entry.js +1 -1
- package/dist/esm/ion-loading.entry.js +1 -1
- package/dist/esm/ion-menu_3.entry.js +1 -1
- package/dist/esm/ion-modal.entry.js +1 -1
- package/dist/esm/ion-popover.entry.js +1 -1
- package/dist/esm/ion-refresher_2.entry.js +18 -1
- package/dist/esm/ion-select-modal.entry.js +1 -1
- package/dist/esm/ion-select_3.entry.js +1 -1
- package/dist/esm/ion-toast.entry.js +1 -1
- package/dist/esm/{overlays-B_dsLNe8.js → overlays-BfCgLYdD.js} +102 -2
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/{p-698fb72c.entry.js → p-1e6a6fde.entry.js} +1 -1
- package/dist/ionic/{p-98d0823e.entry.js → p-31f7216f.entry.js} +1 -1
- package/dist/ionic/{p-57bb1214.entry.js → p-4d57f91a.entry.js} +1 -1
- package/dist/ionic/{p-8bfe00f3.entry.js → p-5c138549.entry.js} +1 -1
- package/dist/ionic/p-8cdb4ff5.entry.js +4 -0
- package/dist/ionic/{p-09ed68cf.entry.js → p-9f8f01e6.entry.js} +1 -1
- package/dist/ionic/{p-84236acb.entry.js → p-b92a19c8.entry.js} +1 -1
- package/dist/ionic/{p-9c6fddc6.entry.js → p-e206b074.entry.js} +1 -1
- package/dist/ionic/{p-8b54aa01.entry.js → p-e61fd4b2.entry.js} +1 -1
- package/dist/ionic/{p-07d8f62a.entry.js → p-eb9b64a6.entry.js} +1 -1
- package/dist/ionic/{p-7ed24ba0.entry.js → p-ef5372b6.entry.js} +1 -1
- package/dist/ionic/p-ly6Zj1CK.js +4 -0
- package/hydrate/index.js +119 -2
- package/hydrate/index.mjs +119 -2
- package/package.json +1 -1
- package/dist/ionic/p-C3MD7jSK.js +0 -4
- package/dist/ionic/p-ac2be9d6.entry.js +0 -4
|
@@ -182,6 +182,14 @@ const Refresher = /*@__PURE__*/ proxyCustomElement(class Refresher extends HTMLE
|
|
|
182
182
|
this.beginRefresh();
|
|
183
183
|
this.didRefresh = true;
|
|
184
184
|
hapticImpact({ style: ImpactStyle.Light });
|
|
185
|
+
/**
|
|
186
|
+
* Clear focus from any active element to prevent scroll jumps
|
|
187
|
+
* when the refresh completes
|
|
188
|
+
*/
|
|
189
|
+
const activeElement = document.activeElement;
|
|
190
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
191
|
+
activeElement.blur();
|
|
192
|
+
}
|
|
185
193
|
/**
|
|
186
194
|
* Translate the content element otherwise when pointer is removed
|
|
187
195
|
* from screen the scroll content will bounce back over the refresher
|
|
@@ -597,6 +605,15 @@ const Refresher = /*@__PURE__*/ proxyCustomElement(class Refresher extends HTMLE
|
|
|
597
605
|
this.state = 8 /* RefresherState.Refreshing */;
|
|
598
606
|
// place the content in a hangout position while it thinks
|
|
599
607
|
this.setCss(this.pullMin, this.snapbackDuration, true, '');
|
|
608
|
+
/**
|
|
609
|
+
* Clear focus from any active element to prevent the browser
|
|
610
|
+
* from restoring focus and causing scroll jumps after refresh.
|
|
611
|
+
* This ensures the view stays at the top after refresh completes.
|
|
612
|
+
*/
|
|
613
|
+
const activeElement = document.activeElement;
|
|
614
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
615
|
+
activeElement.blur();
|
|
616
|
+
}
|
|
600
617
|
// emit "refresh" because it was pulled down far enough
|
|
601
618
|
// and they let go to begin refreshing
|
|
602
619
|
this.ionRefresh.emit({
|
|
@@ -679,7 +696,7 @@ const Refresher = /*@__PURE__*/ proxyCustomElement(class Refresher extends HTMLE
|
|
|
679
696
|
}
|
|
680
697
|
render() {
|
|
681
698
|
const mode = getIonMode(this);
|
|
682
|
-
return (h(Host, { key: '
|
|
699
|
+
return (h(Host, { key: '2d1bd880877b698604542ab2d602d38b9504d975', slot: "fixed", class: {
|
|
683
700
|
[mode]: true,
|
|
684
701
|
// Used internally for styling
|
|
685
702
|
[`refresher-${mode}`]: true,
|
package/components/overlays.js
CHANGED
|
@@ -5,7 +5,7 @@ import { d as doc } from './index9.js';
|
|
|
5
5
|
import { h as focusVisibleElement, c as componentOnReady, a as addEventListener, b as removeEventListener, g as getElementRoot } from './helpers.js';
|
|
6
6
|
import { OVERLAY_BACK_BUTTON_PRIORITY, shouldUseCloseWatcher } from './hardware-back-button.js';
|
|
7
7
|
import { c as config, a as printIonError, p as printIonWarning } from './index4.js';
|
|
8
|
-
import { b as getIonMode } from './ionic-global.js';
|
|
8
|
+
import { b as getIonMode, a as isPlatform } from './ionic-global.js';
|
|
9
9
|
import { C as CoreDelegate } from './framework-delegate.js';
|
|
10
10
|
import { B as BACKDROP_NO_SCROLL } from './gesture-controller.js';
|
|
11
11
|
|
|
@@ -508,6 +508,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
508
508
|
if (overlay.presented) {
|
|
509
509
|
return;
|
|
510
510
|
}
|
|
511
|
+
console.log("presenting overlay...");
|
|
511
512
|
/**
|
|
512
513
|
* Due to accessibility guidelines, toasts do not have
|
|
513
514
|
* focus traps.
|
|
@@ -517,8 +518,9 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
517
518
|
*/
|
|
518
519
|
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
519
520
|
setRootAriaHidden(true);
|
|
520
|
-
document.body.classList.add(BACKDROP_NO_SCROLL);
|
|
521
521
|
}
|
|
522
|
+
hideUnderlyingOverlaysFromScreenReaders(overlay.el);
|
|
523
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
522
524
|
overlay.presented = true;
|
|
523
525
|
overlay.willPresent.emit();
|
|
524
526
|
(_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
|
|
@@ -565,6 +567,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
565
567
|
* screen readers.
|
|
566
568
|
*/
|
|
567
569
|
overlay.el.removeAttribute('aria-hidden');
|
|
570
|
+
overlay.el.removeAttribute('inert');
|
|
568
571
|
};
|
|
569
572
|
/**
|
|
570
573
|
* When an overlay component is dismissed,
|
|
@@ -644,6 +647,12 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
644
647
|
}
|
|
645
648
|
overlay.presented = false;
|
|
646
649
|
try {
|
|
650
|
+
/**
|
|
651
|
+
* There is no need to show the overlay to screen readers during
|
|
652
|
+
* the dismiss animation. This is because the overlay will be removed
|
|
653
|
+
* from the DOM after the animation is complete.
|
|
654
|
+
*/
|
|
655
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
647
656
|
// Overlay contents should not be clickable during dismiss
|
|
648
657
|
overlay.el.style.setProperty('pointer-events', 'none');
|
|
649
658
|
overlay.willDismiss.emit({ data, role });
|
|
@@ -682,6 +691,7 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
682
691
|
printIonError(`[${overlay.el.tagName.toLowerCase()}] - `, err);
|
|
683
692
|
}
|
|
684
693
|
overlay.el.remove();
|
|
694
|
+
revealOverlaysToScreenReaders();
|
|
685
695
|
return true;
|
|
686
696
|
};
|
|
687
697
|
const getAppRoot = (doc) => {
|
|
@@ -877,6 +887,96 @@ const createTriggerController = () => {
|
|
|
877
887
|
removeClickListener,
|
|
878
888
|
};
|
|
879
889
|
};
|
|
890
|
+
/**
|
|
891
|
+
* The overlay that is being animated also needs to hide from screen
|
|
892
|
+
* readers during its animation. This ensures that assistive technologies
|
|
893
|
+
* like TalkBack do not announce or interact with the content until the
|
|
894
|
+
* animation is complete, avoiding confusion for users.
|
|
895
|
+
*
|
|
896
|
+
* When the overlay is presented on an Android device, TalkBack's focus rings
|
|
897
|
+
* may appear in the wrong position due to the transition (specifically
|
|
898
|
+
* `transform` styles). This occurs because the focus rings are initially
|
|
899
|
+
* displayed at the starting position of the elements before the transition
|
|
900
|
+
* begins. This workaround ensures the focus rings do not appear in the
|
|
901
|
+
* incorrect location.
|
|
902
|
+
*
|
|
903
|
+
* If this solution is applied to iOS devices, then it leads to a bug where
|
|
904
|
+
* the overlays cannot be accessed by screen readers. This is due to
|
|
905
|
+
* VoiceOver not being able to update the accessibility tree when the
|
|
906
|
+
* `aria-hidden` is removed.
|
|
907
|
+
*
|
|
908
|
+
* @param overlay - The overlay that is being animated.
|
|
909
|
+
*/
|
|
910
|
+
const hideAnimatingOverlayFromScreenReaders = (overlay) => {
|
|
911
|
+
if (doc === undefined)
|
|
912
|
+
return;
|
|
913
|
+
if (isPlatform('android')) {
|
|
914
|
+
/**
|
|
915
|
+
* Once the animation is complete, this attribute will be removed.
|
|
916
|
+
* This is done at the end of the `present` method.
|
|
917
|
+
*/
|
|
918
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
919
|
+
overlay.setAttribute('inert', '');
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
/**
|
|
923
|
+
* Ensure that underlying overlays have aria-hidden if necessary so that screen readers
|
|
924
|
+
* cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
|
|
925
|
+
* events here because those events do not fire when the screen readers moves to a non-focusable
|
|
926
|
+
* element such as text.
|
|
927
|
+
* Without this logic screen readers would be able to move focus outside of the top focus-trapped overlay.
|
|
928
|
+
*
|
|
929
|
+
* @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
|
|
930
|
+
* fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
|
|
931
|
+
*/
|
|
932
|
+
const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
|
|
933
|
+
var _a;
|
|
934
|
+
if (doc === undefined)
|
|
935
|
+
return;
|
|
936
|
+
const overlays = getPresentedOverlays(doc);
|
|
937
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
938
|
+
const presentedOverlay = overlays[i];
|
|
939
|
+
const nextPresentedOverlay = (_a = overlays[i + 1]) !== null && _a !== void 0 ? _a : newTopMostOverlay;
|
|
940
|
+
/**
|
|
941
|
+
* If next overlay has aria-hidden then all remaining overlays will have it too.
|
|
942
|
+
* Or, if the next overlay is a Toast that does not have aria-hidden then current overlay
|
|
943
|
+
* should not have aria-hidden either so focus can remain in the current overlay.
|
|
944
|
+
*/
|
|
945
|
+
if (nextPresentedOverlay.hasAttribute('aria-hidden') || nextPresentedOverlay.tagName !== 'ION-TOAST') {
|
|
946
|
+
presentedOverlay.setAttribute('aria-hidden', 'true');
|
|
947
|
+
presentedOverlay.setAttribute('inert', '');
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* When dismissing an overlay we need to reveal the new top-most overlay to screen readers.
|
|
953
|
+
* If the top-most overlay is a Toast we potentially need to reveal more overlays since
|
|
954
|
+
* focus is never automatically moved to the Toast.
|
|
955
|
+
*/
|
|
956
|
+
const revealOverlaysToScreenReaders = () => {
|
|
957
|
+
if (doc === undefined)
|
|
958
|
+
return;
|
|
959
|
+
const overlays = getPresentedOverlays(doc);
|
|
960
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
961
|
+
const currentOverlay = overlays[i];
|
|
962
|
+
/**
|
|
963
|
+
* If the current we are looking at is a Toast then we can remove aria-hidden.
|
|
964
|
+
* However, we potentially need to keep looking at the overlay stack because there
|
|
965
|
+
* could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast
|
|
966
|
+
* overlay too so focus can move there since focus is never automatically moved to the Toast.
|
|
967
|
+
*/
|
|
968
|
+
currentOverlay.removeAttribute('aria-hidden');
|
|
969
|
+
currentOverlay.removeAttribute('inert');
|
|
970
|
+
/**
|
|
971
|
+
* If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely
|
|
972
|
+
* since this overlay should always receive focus. As a result, all underlying overlays should still
|
|
973
|
+
* be hidden from screen readers.
|
|
974
|
+
*/
|
|
975
|
+
if (currentOverlay.tagName !== 'ION-TOAST') {
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
};
|
|
880
980
|
const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
|
|
881
981
|
|
|
882
982
|
export { BACKDROP as B, FOCUS_TRAP_DISABLE_CLASS as F, GESTURE as G, OVERLAY_GESTURE_PRIORITY as O, alertController as a, actionSheetController as b, popoverController as c, createDelegateController as d, createTriggerController as e, present as f, dismiss as g, eventMethod as h, isCancel as i, prepareOverlay as j, setOverlayId as k, loadingController as l, modalController as m, focusFirstDescendant as n, getPresentedOverlay as o, pickerController as p, focusLastDescendant as q, safeCall as s, toastController as t };
|
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -15,7 +15,7 @@ var index$2 = require('./index-DNh170BW.js');
|
|
|
15
15
|
var config = require('./config-CKhELRRu.js');
|
|
16
16
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
17
17
|
var index$3 = require('./index-D24wggHR.js');
|
|
18
|
-
var overlays = require('./overlays-
|
|
18
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
19
19
|
require('./index-DkNv4J_i.js');
|
|
20
20
|
require('./gesture-controller-dtqlP_q4.js');
|
|
21
21
|
require('./hardware-back-button-BxdNu76F.js');
|
|
@@ -7,7 +7,7 @@ var index = require('./index-DNh170BW.js');
|
|
|
7
7
|
var buttonActive = require('./button-active-BzZenWWH.js');
|
|
8
8
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
9
9
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
10
|
-
var overlays = require('./overlays-
|
|
10
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
11
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
12
12
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
13
13
|
var animation = require('./animation-ZJ1lAkZD.js');
|
|
@@ -8,7 +8,7 @@ var config = require('./config-CKhELRRu.js');
|
|
|
8
8
|
var buttonActive = require('./button-active-BzZenWWH.js');
|
|
9
9
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
10
10
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
11
|
-
var overlays = require('./overlays-
|
|
11
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
12
12
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
13
13
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
14
14
|
var animation = require('./animation-ZJ1lAkZD.js');
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
var index = require('./index-DNh170BW.js');
|
|
7
7
|
var focusVisible = require('./focus-visible-CCvKiLh3.js');
|
|
8
8
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
9
|
-
var overlays = require('./overlays-
|
|
9
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
10
10
|
var dir = require('./dir-Cn0z1rJH.js');
|
|
11
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
12
12
|
var index$1 = require('./index-DqmRDbxg.js');
|
|
@@ -7,7 +7,7 @@ var index = require('./index-DNh170BW.js');
|
|
|
7
7
|
var config = require('./config-CKhELRRu.js');
|
|
8
8
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
9
9
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
10
|
-
var overlays = require('./overlays-
|
|
10
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
11
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
12
12
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
13
13
|
var animation = require('./animation-ZJ1lAkZD.js');
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
var index = require('./index-DNh170BW.js');
|
|
7
7
|
var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
|
|
8
|
-
var overlays = require('./overlays-
|
|
8
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
9
9
|
var gestureController = require('./gesture-controller-dtqlP_q4.js');
|
|
10
10
|
var hardwareBackButton = require('./hardware-back-button-BxdNu76F.js');
|
|
11
11
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
@@ -9,7 +9,7 @@ var frameworkDelegate = require('./framework-delegate-WkyjrnCx.js');
|
|
|
9
9
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
10
10
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
11
11
|
var capacitor = require('./capacitor-DmA66EwP.js');
|
|
12
|
-
var overlays = require('./overlays-
|
|
12
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
13
13
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
14
14
|
var index$4 = require('./index-BzEyuIww.js');
|
|
15
15
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
var index = require('./index-DNh170BW.js');
|
|
7
|
-
var overlays = require('./overlays-
|
|
7
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
8
8
|
var frameworkDelegate = require('./framework-delegate-WkyjrnCx.js');
|
|
9
9
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
10
10
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
@@ -375,6 +375,14 @@ const Refresher = class {
|
|
|
375
375
|
this.beginRefresh();
|
|
376
376
|
this.didRefresh = true;
|
|
377
377
|
haptic.hapticImpact({ style: haptic.ImpactStyle.Light });
|
|
378
|
+
/**
|
|
379
|
+
* Clear focus from any active element to prevent scroll jumps
|
|
380
|
+
* when the refresh completes
|
|
381
|
+
*/
|
|
382
|
+
const activeElement = document.activeElement;
|
|
383
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
384
|
+
activeElement.blur();
|
|
385
|
+
}
|
|
378
386
|
/**
|
|
379
387
|
* Translate the content element otherwise when pointer is removed
|
|
380
388
|
* from screen the scroll content will bounce back over the refresher
|
|
@@ -790,6 +798,15 @@ const Refresher = class {
|
|
|
790
798
|
this.state = 8 /* RefresherState.Refreshing */;
|
|
791
799
|
// place the content in a hangout position while it thinks
|
|
792
800
|
this.setCss(this.pullMin, this.snapbackDuration, true, '');
|
|
801
|
+
/**
|
|
802
|
+
* Clear focus from any active element to prevent the browser
|
|
803
|
+
* from restoring focus and causing scroll jumps after refresh.
|
|
804
|
+
* This ensures the view stays at the top after refresh completes.
|
|
805
|
+
*/
|
|
806
|
+
const activeElement = document.activeElement;
|
|
807
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
808
|
+
activeElement.blur();
|
|
809
|
+
}
|
|
793
810
|
// emit "refresh" because it was pulled down far enough
|
|
794
811
|
// and they let go to begin refreshing
|
|
795
812
|
this.ionRefresh.emit({
|
|
@@ -872,7 +889,7 @@ const Refresher = class {
|
|
|
872
889
|
}
|
|
873
890
|
render() {
|
|
874
891
|
const mode = ionicGlobal.getIonMode(this);
|
|
875
|
-
return (index.h(index.Host, { key: '
|
|
892
|
+
return (index.h(index.Host, { key: '2d1bd880877b698604542ab2d602d38b9504d975', slot: "fixed", class: {
|
|
876
893
|
[mode]: true,
|
|
877
894
|
// Used internally for styling
|
|
878
895
|
[`refresher-${mode}`]: true,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
var index = require('./index-DNh170BW.js');
|
|
7
7
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
8
|
-
var overlays = require('./overlays-
|
|
8
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
9
9
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
10
10
|
require('./index-DkNv4J_i.js');
|
|
11
11
|
require('./helpers-DgwmcYAu.js');
|
|
@@ -7,7 +7,7 @@ var index = require('./index-DNh170BW.js');
|
|
|
7
7
|
var notchController = require('./notch-controller-Bf5Rr4R5.js');
|
|
8
8
|
var compareWithUtils = require('./compare-with-utils-DSicavqM.js');
|
|
9
9
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
10
|
-
var overlays = require('./overlays-
|
|
10
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
11
11
|
var dir = require('./dir-Cn0z1rJH.js');
|
|
12
12
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
13
13
|
var watchOptions = require('./watch-options-CviOsrTS.js');
|
|
@@ -7,7 +7,7 @@ var index$1 = require('./index-DNh170BW.js');
|
|
|
7
7
|
var config = require('./config-CKhELRRu.js');
|
|
8
8
|
var helpers = require('./helpers-DgwmcYAu.js');
|
|
9
9
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
10
|
-
var overlays = require('./overlays-
|
|
10
|
+
var overlays = require('./overlays-DFkeeMZX.js');
|
|
11
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
12
12
|
var ionicGlobal = require('./ionic-global-UI5YPSi-.js');
|
|
13
13
|
var animation = require('./animation-ZJ1lAkZD.js');
|
|
@@ -510,6 +510,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
510
510
|
if (overlay.presented) {
|
|
511
511
|
return;
|
|
512
512
|
}
|
|
513
|
+
console.log("presenting overlay...");
|
|
513
514
|
/**
|
|
514
515
|
* Due to accessibility guidelines, toasts do not have
|
|
515
516
|
* focus traps.
|
|
@@ -519,8 +520,9 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
519
520
|
*/
|
|
520
521
|
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
521
522
|
setRootAriaHidden(true);
|
|
522
|
-
document.body.classList.add(gestureController.BACKDROP_NO_SCROLL);
|
|
523
523
|
}
|
|
524
|
+
hideUnderlyingOverlaysFromScreenReaders(overlay.el);
|
|
525
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
524
526
|
overlay.presented = true;
|
|
525
527
|
overlay.willPresent.emit();
|
|
526
528
|
(_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
|
|
@@ -567,6 +569,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
567
569
|
* screen readers.
|
|
568
570
|
*/
|
|
569
571
|
overlay.el.removeAttribute('aria-hidden');
|
|
572
|
+
overlay.el.removeAttribute('inert');
|
|
570
573
|
};
|
|
571
574
|
/**
|
|
572
575
|
* When an overlay component is dismissed,
|
|
@@ -646,6 +649,12 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
646
649
|
}
|
|
647
650
|
overlay.presented = false;
|
|
648
651
|
try {
|
|
652
|
+
/**
|
|
653
|
+
* There is no need to show the overlay to screen readers during
|
|
654
|
+
* the dismiss animation. This is because the overlay will be removed
|
|
655
|
+
* from the DOM after the animation is complete.
|
|
656
|
+
*/
|
|
657
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
649
658
|
// Overlay contents should not be clickable during dismiss
|
|
650
659
|
overlay.el.style.setProperty('pointer-events', 'none');
|
|
651
660
|
overlay.willDismiss.emit({ data, role });
|
|
@@ -684,6 +693,7 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
684
693
|
index.printIonError(`[${overlay.el.tagName.toLowerCase()}] - `, err);
|
|
685
694
|
}
|
|
686
695
|
overlay.el.remove();
|
|
696
|
+
revealOverlaysToScreenReaders();
|
|
687
697
|
return true;
|
|
688
698
|
};
|
|
689
699
|
const getAppRoot = (doc) => {
|
|
@@ -879,6 +889,96 @@ const createTriggerController = () => {
|
|
|
879
889
|
removeClickListener,
|
|
880
890
|
};
|
|
881
891
|
};
|
|
892
|
+
/**
|
|
893
|
+
* The overlay that is being animated also needs to hide from screen
|
|
894
|
+
* readers during its animation. This ensures that assistive technologies
|
|
895
|
+
* like TalkBack do not announce or interact with the content until the
|
|
896
|
+
* animation is complete, avoiding confusion for users.
|
|
897
|
+
*
|
|
898
|
+
* When the overlay is presented on an Android device, TalkBack's focus rings
|
|
899
|
+
* may appear in the wrong position due to the transition (specifically
|
|
900
|
+
* `transform` styles). This occurs because the focus rings are initially
|
|
901
|
+
* displayed at the starting position of the elements before the transition
|
|
902
|
+
* begins. This workaround ensures the focus rings do not appear in the
|
|
903
|
+
* incorrect location.
|
|
904
|
+
*
|
|
905
|
+
* If this solution is applied to iOS devices, then it leads to a bug where
|
|
906
|
+
* the overlays cannot be accessed by screen readers. This is due to
|
|
907
|
+
* VoiceOver not being able to update the accessibility tree when the
|
|
908
|
+
* `aria-hidden` is removed.
|
|
909
|
+
*
|
|
910
|
+
* @param overlay - The overlay that is being animated.
|
|
911
|
+
*/
|
|
912
|
+
const hideAnimatingOverlayFromScreenReaders = (overlay) => {
|
|
913
|
+
if (index$1.doc === undefined)
|
|
914
|
+
return;
|
|
915
|
+
if (ionicGlobal.isPlatform('android')) {
|
|
916
|
+
/**
|
|
917
|
+
* Once the animation is complete, this attribute will be removed.
|
|
918
|
+
* This is done at the end of the `present` method.
|
|
919
|
+
*/
|
|
920
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
921
|
+
overlay.setAttribute('inert', '');
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
/**
|
|
925
|
+
* Ensure that underlying overlays have aria-hidden if necessary so that screen readers
|
|
926
|
+
* cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
|
|
927
|
+
* events here because those events do not fire when the screen readers moves to a non-focusable
|
|
928
|
+
* element such as text.
|
|
929
|
+
* Without this logic screen readers would be able to move focus outside of the top focus-trapped overlay.
|
|
930
|
+
*
|
|
931
|
+
* @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
|
|
932
|
+
* fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
|
|
933
|
+
*/
|
|
934
|
+
const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
|
|
935
|
+
var _a;
|
|
936
|
+
if (index$1.doc === undefined)
|
|
937
|
+
return;
|
|
938
|
+
const overlays = getPresentedOverlays(index$1.doc);
|
|
939
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
940
|
+
const presentedOverlay = overlays[i];
|
|
941
|
+
const nextPresentedOverlay = (_a = overlays[i + 1]) !== null && _a !== void 0 ? _a : newTopMostOverlay;
|
|
942
|
+
/**
|
|
943
|
+
* If next overlay has aria-hidden then all remaining overlays will have it too.
|
|
944
|
+
* Or, if the next overlay is a Toast that does not have aria-hidden then current overlay
|
|
945
|
+
* should not have aria-hidden either so focus can remain in the current overlay.
|
|
946
|
+
*/
|
|
947
|
+
if (nextPresentedOverlay.hasAttribute('aria-hidden') || nextPresentedOverlay.tagName !== 'ION-TOAST') {
|
|
948
|
+
presentedOverlay.setAttribute('aria-hidden', 'true');
|
|
949
|
+
presentedOverlay.setAttribute('inert', '');
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
/**
|
|
954
|
+
* When dismissing an overlay we need to reveal the new top-most overlay to screen readers.
|
|
955
|
+
* If the top-most overlay is a Toast we potentially need to reveal more overlays since
|
|
956
|
+
* focus is never automatically moved to the Toast.
|
|
957
|
+
*/
|
|
958
|
+
const revealOverlaysToScreenReaders = () => {
|
|
959
|
+
if (index$1.doc === undefined)
|
|
960
|
+
return;
|
|
961
|
+
const overlays = getPresentedOverlays(index$1.doc);
|
|
962
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
963
|
+
const currentOverlay = overlays[i];
|
|
964
|
+
/**
|
|
965
|
+
* If the current we are looking at is a Toast then we can remove aria-hidden.
|
|
966
|
+
* However, we potentially need to keep looking at the overlay stack because there
|
|
967
|
+
* could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast
|
|
968
|
+
* overlay too so focus can move there since focus is never automatically moved to the Toast.
|
|
969
|
+
*/
|
|
970
|
+
currentOverlay.removeAttribute('aria-hidden');
|
|
971
|
+
currentOverlay.removeAttribute('inert');
|
|
972
|
+
/**
|
|
973
|
+
* If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely
|
|
974
|
+
* since this overlay should always receive focus. As a result, all underlying overlays should still
|
|
975
|
+
* be hidden from screen readers.
|
|
976
|
+
*/
|
|
977
|
+
if (currentOverlay.tagName !== 'ION-TOAST') {
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
};
|
|
882
982
|
const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
|
|
883
983
|
|
|
884
984
|
exports.BACKDROP = BACKDROP;
|
|
@@ -175,6 +175,14 @@ export class Refresher {
|
|
|
175
175
|
this.beginRefresh();
|
|
176
176
|
this.didRefresh = true;
|
|
177
177
|
hapticImpact({ style: ImpactStyle.Light });
|
|
178
|
+
/**
|
|
179
|
+
* Clear focus from any active element to prevent scroll jumps
|
|
180
|
+
* when the refresh completes
|
|
181
|
+
*/
|
|
182
|
+
const activeElement = document.activeElement;
|
|
183
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
184
|
+
activeElement.blur();
|
|
185
|
+
}
|
|
178
186
|
/**
|
|
179
187
|
* Translate the content element otherwise when pointer is removed
|
|
180
188
|
* from screen the scroll content will bounce back over the refresher
|
|
@@ -590,6 +598,15 @@ export class Refresher {
|
|
|
590
598
|
this.state = 8 /* RefresherState.Refreshing */;
|
|
591
599
|
// place the content in a hangout position while it thinks
|
|
592
600
|
this.setCss(this.pullMin, this.snapbackDuration, true, '');
|
|
601
|
+
/**
|
|
602
|
+
* Clear focus from any active element to prevent the browser
|
|
603
|
+
* from restoring focus and causing scroll jumps after refresh.
|
|
604
|
+
* This ensures the view stays at the top after refresh completes.
|
|
605
|
+
*/
|
|
606
|
+
const activeElement = document.activeElement;
|
|
607
|
+
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
|
|
608
|
+
activeElement.blur();
|
|
609
|
+
}
|
|
593
610
|
// emit "refresh" because it was pulled down far enough
|
|
594
611
|
// and they let go to begin refreshing
|
|
595
612
|
this.ionRefresh.emit({
|
|
@@ -672,7 +689,7 @@ export class Refresher {
|
|
|
672
689
|
}
|
|
673
690
|
render() {
|
|
674
691
|
const mode = getIonMode(this);
|
|
675
|
-
return (h(Host, { key: '
|
|
692
|
+
return (h(Host, { key: '2d1bd880877b698604542ab2d602d38b9504d975', slot: "fixed", class: {
|
|
676
693
|
[mode]: true,
|
|
677
694
|
// Used internally for styling
|
|
678
695
|
[`refresher-${mode}`]: true,
|