@ionic/core 8.7.4-dev.11756465095.1387c832 → 8.7.4-dev.11756888693.1b2f4d4a
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-datetime.js +3 -4
- package/components/ion-menu.js +2 -5
- package/components/overlays.js +109 -18
- package/components/picker-column-option.js +4 -4
- package/components/picker-column.js +39 -3
- package/components/select-modal.js +1 -1
- 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 +4 -4
- package/dist/cjs/ion-loading.cjs.entry.js +1 -1
- package/dist/cjs/ion-menu_3.cjs.entry.js +3 -6
- package/dist/cjs/ion-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-picker-column-option.cjs.entry.js +4 -4
- package/dist/cjs/ion-picker-column.cjs.entry.js +39 -3
- package/dist/cjs/ion-popover.cjs.entry.js +1 -1
- package/dist/cjs/ion-select-modal.cjs.entry.js +2 -2
- 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-Di-PotkY.js → overlays-cmlYi6Sc.js} +108 -17
- package/dist/collection/components/datetime/datetime.js +3 -4
- package/dist/collection/components/menu/menu.js +2 -9
- package/dist/collection/components/picker-column/picker-column.js +39 -3
- package/dist/collection/components/picker-column-option/picker-column-option.ios.css +2 -2
- package/dist/collection/components/picker-column-option/picker-column-option.js +1 -1
- package/dist/collection/components/picker-column-option/picker-column-option.md.css +2 -2
- package/dist/collection/components/select-modal/select-modal.ionic.css +4 -0
- package/dist/collection/utils/overlays.js +109 -17
- package/dist/docs.json +1 -5
- 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 +4 -4
- package/dist/esm/ion-loading.entry.js +1 -1
- package/dist/esm/ion-menu_3.entry.js +3 -6
- package/dist/esm/ion-modal.entry.js +1 -1
- package/dist/esm/ion-picker-column-option.entry.js +4 -4
- package/dist/esm/ion-picker-column.entry.js +39 -3
- package/dist/esm/ion-popover.entry.js +1 -1
- package/dist/esm/ion-select-modal.entry.js +2 -2
- package/dist/esm/ion-select_3.entry.js +1 -1
- package/dist/esm/ion-toast.entry.js +1 -1
- package/dist/esm/{overlays-B1-bMbOY.js → overlays-e6TpXUJS.js} +109 -18
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/{p-f0e88837.entry.js → p-0cffd1bf.entry.js} +1 -1
- package/dist/ionic/{p-fcba862e.entry.js → p-1fd86237.entry.js} +1 -1
- package/dist/ionic/{p-db20a452.entry.js → p-34198a78.entry.js} +1 -1
- package/dist/ionic/p-417569b5.entry.js +4 -0
- package/dist/ionic/p-45b08f61.entry.js +4 -0
- package/dist/ionic/p-63b6f13f.entry.js +4 -0
- package/dist/ionic/p-80de7b65.entry.js +4 -0
- package/dist/ionic/{p-00239ebc.entry.js → p-9d9584bd.entry.js} +1 -1
- package/dist/ionic/p-9f1d66d0.entry.js +4 -0
- package/dist/ionic/p-DkI7cEUN.js +4 -0
- package/dist/ionic/{p-c847a353.entry.js → p-bfad272a.entry.js} +1 -1
- package/dist/ionic/{p-361408bb.entry.js → p-d45f502a.entry.js} +1 -1
- package/dist/ionic/{p-3b1c39cf.entry.js → p-f116e723.entry.js} +1 -1
- package/dist/types/components/picker-column/picker-column.d.ts +7 -0
- package/hydrate/index.js +157 -33
- package/hydrate/index.mjs +157 -33
- package/package.json +2 -2
- package/dist/ionic/p-47b803fc.entry.js +0 -4
- package/dist/ionic/p-66b83d63.entry.js +0 -4
- package/dist/ionic/p-9e575e4e.entry.js +0 -4
- package/dist/ionic/p-CKq50gmC.js +0 -4
- package/dist/ionic/p-a953afe2.entry.js +0 -4
- package/dist/ionic/p-f4d11cbb.entry.js +0 -4
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
var index = require('./index-DNh170BW.js');
|
|
7
7
|
var ionicGlobal = require('./ionic-global-RZLbse4y.js');
|
|
8
|
-
var overlays = require('./overlays-
|
|
8
|
+
var overlays = require('./overlays-cmlYi6Sc.js');
|
|
9
9
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
10
10
|
require('./helpers-CYFB2_7O.js');
|
|
11
11
|
require('./focus-visible-BIj-I3-C.js');
|
|
12
12
|
require('./framework-delegate-D94PxJL6.js');
|
|
13
13
|
require('./gesture-controller-dtqlP_q4.js');
|
|
14
14
|
|
|
15
|
-
const selectModalIonicCss = ".sc-ion-select-modal-ionic-h{height:100%}ion-item.sc-ion-select-modal-ionic{--border-width:0}ion-toolbar.sc-ion-select-modal-ionic{font-size:var(--ion-font-size-450, 1.125rem);font-weight:var(--ion-font-weight-medium, 500);letter-spacing:var(--ion-font-letter-spacing-0, 0%);line-height:var(--ion-font-line-height-700, var(--ion-scale-700, 28px));text-decoration:none;text-transform:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(container),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"container\"]{display:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"label\"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"label\"],ion-list.sc-ion-select-modal-ionic ion-checkbox.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-checkbox.sc-ion-select-modal-ionic [part~=\"label\"]{font-size:var(--ion-font-size-400, 1rem);font-weight:var(--ion-font-weight-medium, 500);letter-spacing:var(--ion-font-letter-spacing-0, 0%);line-height:var(--ion-font-line-height-600, var(--ion-scale-600, 24px));text-decoration:none;text-transform:none}.item-radio-checked.sc-ion-select-modal-ionic,.item-checkbox-checked.sc-ion-select-modal-ionic{--background:var(--ion-semantics-primary-100, var(--ion-primitives-blue-100, #f2f4fd));--border-radius:var(--ion-border-radius-400, var(--ion-scale-400, 16px))}ion-content.sc-ion-select-modal-ionic{--padding-start:var(--ion-space-400, var(--ion-scale-400, 16px)) !important;--padding-end:var(--ion-space-400, var(--ion-scale-400, 16px)) !important;--padding-bottom:var(--ion-space-1200, var(--ion-scale-1200, 48px)) !important}";
|
|
15
|
+
const selectModalIonicCss = ".sc-ion-select-modal-ionic-h{height:100%}ion-item.sc-ion-select-modal-ionic{--border-width:0}ion-item.ion-focused.sc-ion-select-modal-ionic::part(native)::after,ion-item.ion-focused.sc-ion-select-modal-ionic [part~=\"native\"]::after{border:none}ion-toolbar.sc-ion-select-modal-ionic{font-size:var(--ion-font-size-450, 1.125rem);font-weight:var(--ion-font-weight-medium, 500);letter-spacing:var(--ion-font-letter-spacing-0, 0%);line-height:var(--ion-font-line-height-700, var(--ion-scale-700, 28px));text-decoration:none;text-transform:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(container),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"container\"]{display:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"label\"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"label\"],ion-list.sc-ion-select-modal-ionic ion-checkbox.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-checkbox.sc-ion-select-modal-ionic [part~=\"label\"]{font-size:var(--ion-font-size-400, 1rem);font-weight:var(--ion-font-weight-medium, 500);letter-spacing:var(--ion-font-letter-spacing-0, 0%);line-height:var(--ion-font-line-height-600, var(--ion-scale-600, 24px));text-decoration:none;text-transform:none}.item-radio-checked.sc-ion-select-modal-ionic,.item-checkbox-checked.sc-ion-select-modal-ionic{--background:var(--ion-semantics-primary-100, var(--ion-primitives-blue-100, #f2f4fd));--border-radius:var(--ion-border-radius-400, var(--ion-scale-400, 16px))}ion-content.sc-ion-select-modal-ionic{--padding-start:var(--ion-space-400, var(--ion-scale-400, 16px)) !important;--padding-end:var(--ion-space-400, var(--ion-scale-400, 16px)) !important;--padding-bottom:var(--ion-space-1200, var(--ion-scale-1200, 48px)) !important}";
|
|
16
16
|
|
|
17
17
|
const selectModalIosCss = ".sc-ion-select-modal-ios-h{height:100%}ion-item.sc-ion-select-modal-ios{--inner-padding-end:0}ion-radio.sc-ion-select-modal-ios::after{bottom:0;position:absolute;width:calc(100% - 0.9375rem - 16px);border-width:0px 0px 0.55px 0px;border-style:solid;border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));content:\"\"}ion-radio.sc-ion-select-modal-ios::after{inset-inline-start:calc(0.9375rem + 16px)}";
|
|
18
18
|
|
|
@@ -8,7 +8,7 @@ var caretDown = require('./caret-down-vtVgfXIs.js');
|
|
|
8
8
|
var notchController = require('./notch-controller-BmjMp6Co.js');
|
|
9
9
|
var compareWithUtils = require('./compare-with-utils-DSicavqM.js');
|
|
10
10
|
var helpers = require('./helpers-CYFB2_7O.js');
|
|
11
|
-
var overlays = require('./overlays-
|
|
11
|
+
var overlays = require('./overlays-cmlYi6Sc.js');
|
|
12
12
|
var dir = require('./dir-Cn0z1rJH.js');
|
|
13
13
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
14
14
|
var watchOptions = require('./watch-options-CviOsrTS.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-CYFB2_7O.js');
|
|
9
9
|
var lockController = require('./lock-controller-aDB9wrEf.js');
|
|
10
|
-
var overlays = require('./overlays-
|
|
10
|
+
var overlays = require('./overlays-cmlYi6Sc.js');
|
|
11
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
12
12
|
var ionicGlobal = require('./ionic-global-RZLbse4y.js');
|
|
13
13
|
var animation = require('./animation-BXRtNUgm.js');
|
|
@@ -490,17 +490,15 @@ const getPresentedOverlay = (doc, overlayTag, id) => {
|
|
|
490
490
|
*/
|
|
491
491
|
const setRootAriaHidden = (hidden = false) => {
|
|
492
492
|
const root = getAppRoot(document);
|
|
493
|
-
const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
|
|
493
|
+
const viewContainer = root.querySelector('ion-router-outlet, ion-nav, #ion-view-container-root');
|
|
494
494
|
if (!viewContainer) {
|
|
495
495
|
return;
|
|
496
496
|
}
|
|
497
497
|
if (hidden) {
|
|
498
498
|
viewContainer.setAttribute('aria-hidden', 'true');
|
|
499
|
-
viewContainer.setAttribute('inert', '');
|
|
500
499
|
}
|
|
501
500
|
else {
|
|
502
501
|
viewContainer.removeAttribute('aria-hidden');
|
|
503
|
-
viewContainer.removeAttribute('inert');
|
|
504
502
|
}
|
|
505
503
|
};
|
|
506
504
|
const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts) => {
|
|
@@ -508,17 +506,6 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
508
506
|
if (overlay.presented) {
|
|
509
507
|
return;
|
|
510
508
|
}
|
|
511
|
-
/**
|
|
512
|
-
* When an overlay that steals focus
|
|
513
|
-
* is dismissed, focus should be returned
|
|
514
|
-
* to the element that was focused
|
|
515
|
-
* prior to the overlay opening. Toast
|
|
516
|
-
* does not steal focus and is excluded
|
|
517
|
-
* from returning focus as a result.
|
|
518
|
-
*/
|
|
519
|
-
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
520
|
-
restoreElementFocus(overlay.el);
|
|
521
|
-
}
|
|
522
509
|
/**
|
|
523
510
|
* Due to accessibility guidelines, toasts do not have
|
|
524
511
|
* focus traps.
|
|
@@ -530,6 +517,8 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
530
517
|
setRootAriaHidden(true);
|
|
531
518
|
document.body.classList.add(gestureController.BACKDROP_NO_SCROLL);
|
|
532
519
|
}
|
|
520
|
+
hideUnderlyingOverlaysFromScreenReaders(overlay.el);
|
|
521
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
533
522
|
overlay.presented = true;
|
|
534
523
|
overlay.willPresent.emit();
|
|
535
524
|
(_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
|
|
@@ -543,6 +532,17 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
543
532
|
overlay.didPresent.emit();
|
|
544
533
|
(_b = overlay.didPresentShorthand) === null || _b === void 0 ? void 0 : _b.emit();
|
|
545
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* When an overlay that steals focus
|
|
537
|
+
* is dismissed, focus should be returned
|
|
538
|
+
* to the element that was focused
|
|
539
|
+
* prior to the overlay opening. Toast
|
|
540
|
+
* does not steal focus and is excluded
|
|
541
|
+
* from returning focus as a result.
|
|
542
|
+
*/
|
|
543
|
+
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
544
|
+
restoreElementFocus(overlay.el);
|
|
545
|
+
}
|
|
546
546
|
/**
|
|
547
547
|
* If the focused element is already
|
|
548
548
|
* inside the overlay component then
|
|
@@ -565,7 +565,6 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
|
|
|
565
565
|
* screen readers.
|
|
566
566
|
*/
|
|
567
567
|
overlay.el.removeAttribute('aria-hidden');
|
|
568
|
-
overlay.el.removeAttribute('inert');
|
|
569
568
|
};
|
|
570
569
|
/**
|
|
571
570
|
* When an overlay component is dismissed,
|
|
@@ -582,8 +581,6 @@ const restoreElementFocus = async (overlayEl) => {
|
|
|
582
581
|
if (!previousElement) {
|
|
583
582
|
return;
|
|
584
583
|
}
|
|
585
|
-
// Ensure active element is blurred to prevent a11y warning issues
|
|
586
|
-
previousElement.blur();
|
|
587
584
|
const shadowRoot = previousElement === null || previousElement === void 0 ? void 0 : previousElement.shadowRoot;
|
|
588
585
|
if (shadowRoot) {
|
|
589
586
|
// If there are no inner focusable elements, just focus the host element.
|
|
@@ -647,6 +644,12 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
647
644
|
}
|
|
648
645
|
overlay.presented = false;
|
|
649
646
|
try {
|
|
647
|
+
/**
|
|
648
|
+
* There is no need to show the overlay to screen readers during
|
|
649
|
+
* the dismiss animation. This is because the overlay will be removed
|
|
650
|
+
* from the DOM after the animation is complete.
|
|
651
|
+
*/
|
|
652
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
650
653
|
// Overlay contents should not be clickable during dismiss
|
|
651
654
|
overlay.el.style.setProperty('pointer-events', 'none');
|
|
652
655
|
overlay.willDismiss.emit({ data, role });
|
|
@@ -685,6 +688,7 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
|
|
|
685
688
|
index.printIonError(`[${overlay.el.tagName.toLowerCase()}] - `, err);
|
|
686
689
|
}
|
|
687
690
|
overlay.el.remove();
|
|
691
|
+
revealOverlaysToScreenReaders();
|
|
688
692
|
return true;
|
|
689
693
|
};
|
|
690
694
|
const getAppRoot = (doc) => {
|
|
@@ -881,6 +885,93 @@ const createTriggerController = () => {
|
|
|
881
885
|
removeClickListener,
|
|
882
886
|
};
|
|
883
887
|
};
|
|
888
|
+
/**
|
|
889
|
+
* The overlay that is being animated also needs to hide from screen
|
|
890
|
+
* readers during its animation. This ensures that assistive technologies
|
|
891
|
+
* like TalkBack do not announce or interact with the content until the
|
|
892
|
+
* animation is complete, avoiding confusion for users.
|
|
893
|
+
*
|
|
894
|
+
* When the overlay is presented on an Android device, TalkBack's focus rings
|
|
895
|
+
* may appear in the wrong position due to the transition (specifically
|
|
896
|
+
* `transform` styles). This occurs because the focus rings are initially
|
|
897
|
+
* displayed at the starting position of the elements before the transition
|
|
898
|
+
* begins. This workaround ensures the focus rings do not appear in the
|
|
899
|
+
* incorrect location.
|
|
900
|
+
*
|
|
901
|
+
* If this solution is applied to iOS devices, then it leads to a bug where
|
|
902
|
+
* the overlays cannot be accessed by screen readers. This is due to
|
|
903
|
+
* VoiceOver not being able to update the accessibility tree when the
|
|
904
|
+
* `aria-hidden` is removed.
|
|
905
|
+
*
|
|
906
|
+
* @param overlay - The overlay that is being animated.
|
|
907
|
+
*/
|
|
908
|
+
const hideAnimatingOverlayFromScreenReaders = (overlay) => {
|
|
909
|
+
if (ionicGlobal.doc === undefined)
|
|
910
|
+
return;
|
|
911
|
+
if (ionicGlobal.isPlatform('android')) {
|
|
912
|
+
/**
|
|
913
|
+
* Once the animation is complete, this attribute will be removed.
|
|
914
|
+
* This is done at the end of the `present` method.
|
|
915
|
+
*/
|
|
916
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
/**
|
|
920
|
+
* Ensure that underlying overlays have aria-hidden if necessary so that screen readers
|
|
921
|
+
* cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
|
|
922
|
+
* events here because those events do not fire when the screen readers moves to a non-focusable
|
|
923
|
+
* element such as text.
|
|
924
|
+
* Without this logic screen readers would be able to move focus outside of the top focus-trapped overlay.
|
|
925
|
+
*
|
|
926
|
+
* @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
|
|
927
|
+
* fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
|
|
928
|
+
*/
|
|
929
|
+
const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
|
|
930
|
+
var _a;
|
|
931
|
+
if (ionicGlobal.doc === undefined)
|
|
932
|
+
return;
|
|
933
|
+
const overlays = getPresentedOverlays(ionicGlobal.doc);
|
|
934
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
935
|
+
const presentedOverlay = overlays[i];
|
|
936
|
+
const nextPresentedOverlay = (_a = overlays[i + 1]) !== null && _a !== void 0 ? _a : newTopMostOverlay;
|
|
937
|
+
/**
|
|
938
|
+
* If next overlay has aria-hidden then all remaining overlays will have it too.
|
|
939
|
+
* Or, if the next overlay is a Toast that does not have aria-hidden then current overlay
|
|
940
|
+
* should not have aria-hidden either so focus can remain in the current overlay.
|
|
941
|
+
*/
|
|
942
|
+
if (nextPresentedOverlay.hasAttribute('aria-hidden') || nextPresentedOverlay.tagName !== 'ION-TOAST') {
|
|
943
|
+
presentedOverlay.setAttribute('aria-hidden', 'true');
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
/**
|
|
948
|
+
* When dismissing an overlay we need to reveal the new top-most overlay to screen readers.
|
|
949
|
+
* If the top-most overlay is a Toast we potentially need to reveal more overlays since
|
|
950
|
+
* focus is never automatically moved to the Toast.
|
|
951
|
+
*/
|
|
952
|
+
const revealOverlaysToScreenReaders = () => {
|
|
953
|
+
if (ionicGlobal.doc === undefined)
|
|
954
|
+
return;
|
|
955
|
+
const overlays = getPresentedOverlays(ionicGlobal.doc);
|
|
956
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
957
|
+
const currentOverlay = overlays[i];
|
|
958
|
+
/**
|
|
959
|
+
* If the current we are looking at is a Toast then we can remove aria-hidden.
|
|
960
|
+
* However, we potentially need to keep looking at the overlay stack because there
|
|
961
|
+
* could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast
|
|
962
|
+
* overlay too so focus can move there since focus is never automatically moved to the Toast.
|
|
963
|
+
*/
|
|
964
|
+
currentOverlay.removeAttribute('aria-hidden');
|
|
965
|
+
/**
|
|
966
|
+
* If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely
|
|
967
|
+
* since this overlay should always receive focus. As a result, all underlying overlays should still
|
|
968
|
+
* be hidden from screen readers.
|
|
969
|
+
*/
|
|
970
|
+
if (currentOverlay.tagName !== 'ION-TOAST') {
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
};
|
|
884
975
|
const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
|
|
885
976
|
|
|
886
977
|
exports.BACKDROP = BACKDROP;
|
|
@@ -7,7 +7,6 @@ import { Host, h, writeTask } from "@stencil/core";
|
|
|
7
7
|
import { startFocusVisible } from "../../utils/focus-visible";
|
|
8
8
|
import { getElementRoot, raf, renderHiddenInput } from "../../utils/helpers";
|
|
9
9
|
import { printIonError, printIonWarning } from "../../utils/logging/index";
|
|
10
|
-
import { FOCUS_TRAP_DISABLE_CLASS } from "../../utils/overlays";
|
|
11
10
|
import { isRTL } from "../../utils/rtl/index";
|
|
12
11
|
import { createColorClasses } from "../../utils/theme";
|
|
13
12
|
import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward } from "ionicons/icons";
|
|
@@ -1106,7 +1105,7 @@ export class Datetime {
|
|
|
1106
1105
|
const renderArray = forcePresentation === 'time-date'
|
|
1107
1106
|
? [this.renderTimePickerColumns(forcePresentation), this.renderDatePickerColumns(forcePresentation)]
|
|
1108
1107
|
: [this.renderDatePickerColumns(forcePresentation), this.renderTimePickerColumns(forcePresentation)];
|
|
1109
|
-
return h("ion-picker",
|
|
1108
|
+
return h("ion-picker", null, renderArray);
|
|
1110
1109
|
}
|
|
1111
1110
|
renderDatePickerColumns(forcePresentation) {
|
|
1112
1111
|
return forcePresentation === 'date-time' || forcePresentation === 'time-date'
|
|
@@ -1733,7 +1732,7 @@ export class Datetime {
|
|
|
1733
1732
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1734
1733
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1735
1734
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1736
|
-
return (h(Host, { key: '
|
|
1735
|
+
return (h(Host, { key: '40f8732998d123ef5c700080cc423bb8310654d5', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1737
1736
|
[theme]: true,
|
|
1738
1737
|
['datetime-readonly']: readonly,
|
|
1739
1738
|
['datetime-disabled']: disabled,
|
|
@@ -1743,7 +1742,7 @@ export class Datetime {
|
|
|
1743
1742
|
[`datetime-size-${size}`]: true,
|
|
1744
1743
|
[`datetime-prefer-wheel`]: hasWheelVariant,
|
|
1745
1744
|
[`datetime-grid`]: isGridStyle,
|
|
1746
|
-
})) }, h("div", { key: '
|
|
1745
|
+
})) }, h("div", { key: '0a323aa4e3cd9c96495d0dc3bf7985c8723f5e8c', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(theme)));
|
|
1747
1746
|
}
|
|
1748
1747
|
static get is() { return "ion-datetime"; }
|
|
1749
1748
|
static get encapsulation() { return "shadow"; }
|
|
@@ -296,9 +296,6 @@ export class Menu {
|
|
|
296
296
|
* @param role The role of the element that is closing the menu.
|
|
297
297
|
*/
|
|
298
298
|
setOpen(shouldOpen, animated = true, role) {
|
|
299
|
-
var _a;
|
|
300
|
-
// Blur the active element to prevent it from being kept focused inside an element that will be set with aria-hidden="true"
|
|
301
|
-
(_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.blur();
|
|
302
299
|
return menuController._setOpen(this, shouldOpen, animated, role);
|
|
303
300
|
}
|
|
304
301
|
trapKeyboardFocus(ev, doc) {
|
|
@@ -661,14 +658,14 @@ export class Menu {
|
|
|
661
658
|
* the ionBackButton listener in the menu controller
|
|
662
659
|
* will handle closing the menu when Escape is pressed.
|
|
663
660
|
*/
|
|
664
|
-
return (h(Host, { key: '
|
|
661
|
+
return (h(Host, { key: 'b0e4627dc1a53c796913d3da9b7575f0d69086d0', onKeyDown: shouldUseCloseWatcher() ? null : this.onKeydown, role: "navigation", "aria-label": inheritedAttributes['aria-label'] || 'menu', class: {
|
|
665
662
|
[theme]: true,
|
|
666
663
|
[`menu-type-${type}`]: true,
|
|
667
664
|
'menu-enabled': !disabled,
|
|
668
665
|
[`menu-side-${side}`]: true,
|
|
669
666
|
'menu-pane-visible': isPaneVisible,
|
|
670
667
|
'split-pane-side': hostContext('ion-split-pane', el),
|
|
671
|
-
} }, h("div", { key: '
|
|
668
|
+
} }, h("div", { key: '6733a5a84b2bcb8f52fb2bac1c286ab5ac1a9321', class: "menu-inner", part: "container", ref: (el) => (this.menuInnerEl = el) }, h("slot", { key: 'a527ba8092d9eb1ee570f3bdd47c6d4d35cd4dfd' })), h("ion-backdrop", { key: '693c82c16d5110cc08eb651309d092a848329cc1', ref: (el) => (this.backdropEl = el), class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
|
|
672
669
|
}
|
|
673
670
|
static get is() { return "ion-menu"; }
|
|
674
671
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1079,10 +1076,6 @@ export class Menu {
|
|
|
1079
1076
|
"Promise": {
|
|
1080
1077
|
"location": "global",
|
|
1081
1078
|
"id": "global::Promise"
|
|
1082
|
-
},
|
|
1083
|
-
"HTMLElement": {
|
|
1084
|
-
"location": "global",
|
|
1085
|
-
"id": "global::HTMLElement"
|
|
1086
1079
|
}
|
|
1087
1080
|
},
|
|
1088
1081
|
"return": "Promise<boolean>"
|
|
@@ -412,6 +412,23 @@ export class PickerColumn {
|
|
|
412
412
|
var _a;
|
|
413
413
|
return el ? (_a = el.getAttribute('aria-label')) !== null && _a !== void 0 ? _a : el.innerText : '';
|
|
414
414
|
};
|
|
415
|
+
/**
|
|
416
|
+
* Render an element that overlays the column. This element is for assistive
|
|
417
|
+
* tech to allow users to navigate the column up/down. This element should receive
|
|
418
|
+
* focus as it listens for synthesized keyboard events as required by the
|
|
419
|
+
* slider role: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/slider_role
|
|
420
|
+
*/
|
|
421
|
+
this.renderAssistiveFocusable = () => {
|
|
422
|
+
const { activeItem } = this;
|
|
423
|
+
const valueText = this.getOptionValueText(activeItem);
|
|
424
|
+
/**
|
|
425
|
+
* When using the picker, the valuetext provides important context that valuenow
|
|
426
|
+
* does not. Additionally, using non-zero valuemin/valuemax values can cause
|
|
427
|
+
* WebKit to incorrectly announce numeric valuetext values (such as a year
|
|
428
|
+
* like "2024") as percentages: https://bugs.webkit.org/show_bug.cgi?id=273126
|
|
429
|
+
*/
|
|
430
|
+
return (h("div", { ref: (el) => (this.assistiveFocusable = el), class: "assistive-focusable", role: "slider", tabindex: this.disabled ? undefined : 0, "aria-label": this.ariaLabel, "aria-valuemin": 0, "aria-valuemax": 0, "aria-valuenow": 0, "aria-valuetext": valueText, "aria-orientation": "vertical", onKeyDown: (ev) => this.onKeyDown(ev) }));
|
|
431
|
+
};
|
|
415
432
|
}
|
|
416
433
|
ariaLabelChanged(newValue) {
|
|
417
434
|
this.ariaLabel = newValue;
|
|
@@ -552,14 +569,33 @@ export class PickerColumn {
|
|
|
552
569
|
render() {
|
|
553
570
|
const { color, disabled, isActive, numericInput } = this;
|
|
554
571
|
const theme = getIonTheme(this);
|
|
555
|
-
return (h(Host, { key: '
|
|
572
|
+
return (h(Host, { key: '03736b14a79aaadec0f7bdac8b61584bd87ccad0', class: createColorClasses(color, {
|
|
556
573
|
[theme]: true,
|
|
557
574
|
['picker-column-active']: isActive,
|
|
558
575
|
['picker-column-numeric-input']: numericInput,
|
|
559
576
|
['picker-column-disabled']: disabled,
|
|
560
|
-
}) }, h("slot", { key: '
|
|
577
|
+
}) }, this.renderAssistiveFocusable(), h("slot", { key: '68c982ebabe6549bda8473b5e75fe1a2a5bfac02', name: "prefix" }), h("div", { key: '9347af6d92c2743262627f0e22cd2ab6e36697fa', "aria-hidden": "true", class: "picker-opts", ref: (el) => {
|
|
561
578
|
this.scrollEl = el;
|
|
562
|
-
},
|
|
579
|
+
},
|
|
580
|
+
/**
|
|
581
|
+
* When an element has an overlay scroll style and
|
|
582
|
+
* a fixed height, Firefox will focus the scrollable
|
|
583
|
+
* container if the content exceeds the container's
|
|
584
|
+
* dimensions.
|
|
585
|
+
*
|
|
586
|
+
* This causes keyboard navigation to focus to this
|
|
587
|
+
* element instead of going to the next element in
|
|
588
|
+
* the tab order.
|
|
589
|
+
*
|
|
590
|
+
* The desired behavior is for the user to be able to
|
|
591
|
+
* focus the assistive focusable element and tab to
|
|
592
|
+
* the next element in the tab order. Instead of tabbing
|
|
593
|
+
* to this element.
|
|
594
|
+
*
|
|
595
|
+
* To prevent this, we set the tabIndex to -1. This
|
|
596
|
+
* will match the behavior of the other browsers.
|
|
597
|
+
*/
|
|
598
|
+
tabIndex: -1 }, h("div", { key: '48aa739ea118e6c6c92dd32aa669afc8cbc9bbd9', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '4c5acf2374d2ad96c3cc0e927023d2ba8615ce4d', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: 'ae5cad7c4deeb08619d4021dfa1f2ba7d0cd9c09', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("slot", { key: '076bb7a8359908369b56ad8021d812fa0d094f5b' }), h("div", { key: '7cf4d0a8d32a9c304fbdb7469c2a5528b91744b9', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '2c6585e2091abc2b83dc77c419d5a8a4d317f499', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '2ee73069dede56b1edc0adfd3037ff0f83389c3e', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0")), h("slot", { key: 'f704bf80e0a0c91d0a50114cba974bbb9d7937d1', name: "suffix" })));
|
|
563
599
|
}
|
|
564
600
|
static get is() { return "ion-picker-column"; }
|
|
565
601
|
static get encapsulation() { return "shadow"; }
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
* }
|
|
60
60
|
* }
|
|
61
61
|
*/
|
|
62
|
-
|
|
62
|
+
button {
|
|
63
63
|
padding-left: 0;
|
|
64
64
|
padding-right: 0;
|
|
65
65
|
padding-top: 0;
|
|
@@ -88,6 +88,6 @@
|
|
|
88
88
|
opacity: 0.4;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
:host(.option-disabled)
|
|
91
|
+
:host(.option-disabled) button {
|
|
92
92
|
cursor: default;
|
|
93
93
|
}
|
|
@@ -98,7 +98,7 @@ export class PickerColumnOption {
|
|
|
98
98
|
return (h(Host, { key: '9ceebae71b6df0b01f36691d82d716f6756625d9', class: createColorClasses(color, {
|
|
99
99
|
[theme]: true,
|
|
100
100
|
['option-disabled']: disabled,
|
|
101
|
-
}) }, h("
|
|
101
|
+
}) }, h("button", { key: 'f6b973f486688a74a08b60c09ab41b640e49db6b', tabindex: "-1", "aria-label": ariaLabel, disabled: disabled, onClick: () => this.onClick() }, h("slot", { key: 'ff9607efb6a87c60c9421c32c81612e4650c6862' }))));
|
|
102
102
|
}
|
|
103
103
|
static get is() { return "ion-picker-column-option"; }
|
|
104
104
|
static get encapsulation() { return "shadow"; }
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
* }
|
|
60
60
|
* }
|
|
61
61
|
*/
|
|
62
|
-
|
|
62
|
+
button {
|
|
63
63
|
padding-left: 0;
|
|
64
64
|
padding-right: 0;
|
|
65
65
|
padding-top: 0;
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
opacity: 0.4;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
:host(.option-disabled)
|
|
91
|
+
:host(.option-disabled) button {
|
|
92
92
|
cursor: default;
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -11,6 +11,7 @@ import { CoreDelegate } from "./framework-delegate";
|
|
|
11
11
|
import { BACKDROP_NO_SCROLL } from "./gesture/gesture-controller";
|
|
12
12
|
import { OVERLAY_BACK_BUTTON_PRIORITY } from "./hardware-back-button";
|
|
13
13
|
import { addEventListener, componentOnReady, focusVisibleElement, getElementRoot, removeEventListener, } from "./helpers";
|
|
14
|
+
import { isPlatform } from "./platform";
|
|
14
15
|
let lastOverlayIndex = 0;
|
|
15
16
|
let lastId = 0;
|
|
16
17
|
export const activeAnimations = new WeakMap();
|
|
@@ -411,17 +412,15 @@ export const getPresentedOverlay = (doc, overlayTag, id) => {
|
|
|
411
412
|
*/
|
|
412
413
|
export const setRootAriaHidden = (hidden = false) => {
|
|
413
414
|
const root = getAppRoot(document);
|
|
414
|
-
const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
|
|
415
|
+
const viewContainer = root.querySelector('ion-router-outlet, ion-nav, #ion-view-container-root');
|
|
415
416
|
if (!viewContainer) {
|
|
416
417
|
return;
|
|
417
418
|
}
|
|
418
419
|
if (hidden) {
|
|
419
420
|
viewContainer.setAttribute('aria-hidden', 'true');
|
|
420
|
-
viewContainer.setAttribute('inert', '');
|
|
421
421
|
}
|
|
422
422
|
else {
|
|
423
423
|
viewContainer.removeAttribute('aria-hidden');
|
|
424
|
-
viewContainer.removeAttribute('inert');
|
|
425
424
|
}
|
|
426
425
|
};
|
|
427
426
|
export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts) => {
|
|
@@ -429,17 +428,6 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
|
|
|
429
428
|
if (overlay.presented) {
|
|
430
429
|
return;
|
|
431
430
|
}
|
|
432
|
-
/**
|
|
433
|
-
* When an overlay that steals focus
|
|
434
|
-
* is dismissed, focus should be returned
|
|
435
|
-
* to the element that was focused
|
|
436
|
-
* prior to the overlay opening. Toast
|
|
437
|
-
* does not steal focus and is excluded
|
|
438
|
-
* from returning focus as a result.
|
|
439
|
-
*/
|
|
440
|
-
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
441
|
-
restoreElementFocus(overlay.el);
|
|
442
|
-
}
|
|
443
431
|
/**
|
|
444
432
|
* Due to accessibility guidelines, toasts do not have
|
|
445
433
|
* focus traps.
|
|
@@ -451,6 +439,8 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
|
|
|
451
439
|
setRootAriaHidden(true);
|
|
452
440
|
document.body.classList.add(BACKDROP_NO_SCROLL);
|
|
453
441
|
}
|
|
442
|
+
hideUnderlyingOverlaysFromScreenReaders(overlay.el);
|
|
443
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
454
444
|
overlay.presented = true;
|
|
455
445
|
overlay.willPresent.emit();
|
|
456
446
|
(_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
|
|
@@ -464,6 +454,17 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
|
|
|
464
454
|
overlay.didPresent.emit();
|
|
465
455
|
(_b = overlay.didPresentShorthand) === null || _b === void 0 ? void 0 : _b.emit();
|
|
466
456
|
}
|
|
457
|
+
/**
|
|
458
|
+
* When an overlay that steals focus
|
|
459
|
+
* is dismissed, focus should be returned
|
|
460
|
+
* to the element that was focused
|
|
461
|
+
* prior to the overlay opening. Toast
|
|
462
|
+
* does not steal focus and is excluded
|
|
463
|
+
* from returning focus as a result.
|
|
464
|
+
*/
|
|
465
|
+
if (overlay.el.tagName !== 'ION-TOAST') {
|
|
466
|
+
restoreElementFocus(overlay.el);
|
|
467
|
+
}
|
|
467
468
|
/**
|
|
468
469
|
* If the focused element is already
|
|
469
470
|
* inside the overlay component then
|
|
@@ -486,7 +487,6 @@ export const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation
|
|
|
486
487
|
* screen readers.
|
|
487
488
|
*/
|
|
488
489
|
overlay.el.removeAttribute('aria-hidden');
|
|
489
|
-
overlay.el.removeAttribute('inert');
|
|
490
490
|
};
|
|
491
491
|
/**
|
|
492
492
|
* When an overlay component is dismissed,
|
|
@@ -503,8 +503,6 @@ const restoreElementFocus = async (overlayEl) => {
|
|
|
503
503
|
if (!previousElement) {
|
|
504
504
|
return;
|
|
505
505
|
}
|
|
506
|
-
// Ensure active element is blurred to prevent a11y warning issues
|
|
507
|
-
previousElement.blur();
|
|
508
506
|
const shadowRoot = previousElement === null || previousElement === void 0 ? void 0 : previousElement.shadowRoot;
|
|
509
507
|
if (shadowRoot) {
|
|
510
508
|
// If there are no inner focusable elements, just focus the host element.
|
|
@@ -568,6 +566,12 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
|
|
|
568
566
|
}
|
|
569
567
|
overlay.presented = false;
|
|
570
568
|
try {
|
|
569
|
+
/**
|
|
570
|
+
* There is no need to show the overlay to screen readers during
|
|
571
|
+
* the dismiss animation. This is because the overlay will be removed
|
|
572
|
+
* from the DOM after the animation is complete.
|
|
573
|
+
*/
|
|
574
|
+
hideAnimatingOverlayFromScreenReaders(overlay.el);
|
|
571
575
|
// Overlay contents should not be clickable during dismiss
|
|
572
576
|
overlay.el.style.setProperty('pointer-events', 'none');
|
|
573
577
|
overlay.willDismiss.emit({ data, role });
|
|
@@ -606,6 +610,7 @@ export const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLe
|
|
|
606
610
|
printIonError(`[${overlay.el.tagName.toLowerCase()}] - `, err);
|
|
607
611
|
}
|
|
608
612
|
overlay.el.remove();
|
|
613
|
+
revealOverlaysToScreenReaders();
|
|
609
614
|
return true;
|
|
610
615
|
};
|
|
611
616
|
const getAppRoot = (doc) => {
|
|
@@ -802,4 +807,91 @@ export const createTriggerController = () => {
|
|
|
802
807
|
removeClickListener,
|
|
803
808
|
};
|
|
804
809
|
};
|
|
810
|
+
/**
|
|
811
|
+
* The overlay that is being animated also needs to hide from screen
|
|
812
|
+
* readers during its animation. This ensures that assistive technologies
|
|
813
|
+
* like TalkBack do not announce or interact with the content until the
|
|
814
|
+
* animation is complete, avoiding confusion for users.
|
|
815
|
+
*
|
|
816
|
+
* When the overlay is presented on an Android device, TalkBack's focus rings
|
|
817
|
+
* may appear in the wrong position due to the transition (specifically
|
|
818
|
+
* `transform` styles). This occurs because the focus rings are initially
|
|
819
|
+
* displayed at the starting position of the elements before the transition
|
|
820
|
+
* begins. This workaround ensures the focus rings do not appear in the
|
|
821
|
+
* incorrect location.
|
|
822
|
+
*
|
|
823
|
+
* If this solution is applied to iOS devices, then it leads to a bug where
|
|
824
|
+
* the overlays cannot be accessed by screen readers. This is due to
|
|
825
|
+
* VoiceOver not being able to update the accessibility tree when the
|
|
826
|
+
* `aria-hidden` is removed.
|
|
827
|
+
*
|
|
828
|
+
* @param overlay - The overlay that is being animated.
|
|
829
|
+
*/
|
|
830
|
+
const hideAnimatingOverlayFromScreenReaders = (overlay) => {
|
|
831
|
+
if (doc === undefined)
|
|
832
|
+
return;
|
|
833
|
+
if (isPlatform('android')) {
|
|
834
|
+
/**
|
|
835
|
+
* Once the animation is complete, this attribute will be removed.
|
|
836
|
+
* This is done at the end of the `present` method.
|
|
837
|
+
*/
|
|
838
|
+
overlay.setAttribute('aria-hidden', 'true');
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
/**
|
|
842
|
+
* Ensure that underlying overlays have aria-hidden if necessary so that screen readers
|
|
843
|
+
* cannot move focus to these elements. Note that we cannot rely on focus/focusin/focusout
|
|
844
|
+
* events here because those events do not fire when the screen readers moves to a non-focusable
|
|
845
|
+
* element such as text.
|
|
846
|
+
* Without this logic screen readers would be able to move focus outside of the top focus-trapped overlay.
|
|
847
|
+
*
|
|
848
|
+
* @param newTopMostOverlay - The overlay that is being presented. Since the overlay has not been
|
|
849
|
+
* fully presented yet at the time this function is called it will not be included in the getPresentedOverlays result.
|
|
850
|
+
*/
|
|
851
|
+
const hideUnderlyingOverlaysFromScreenReaders = (newTopMostOverlay) => {
|
|
852
|
+
var _a;
|
|
853
|
+
if (doc === undefined)
|
|
854
|
+
return;
|
|
855
|
+
const overlays = getPresentedOverlays(doc);
|
|
856
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
857
|
+
const presentedOverlay = overlays[i];
|
|
858
|
+
const nextPresentedOverlay = (_a = overlays[i + 1]) !== null && _a !== void 0 ? _a : newTopMostOverlay;
|
|
859
|
+
/**
|
|
860
|
+
* If next overlay has aria-hidden then all remaining overlays will have it too.
|
|
861
|
+
* Or, if the next overlay is a Toast that does not have aria-hidden then current overlay
|
|
862
|
+
* should not have aria-hidden either so focus can remain in the current overlay.
|
|
863
|
+
*/
|
|
864
|
+
if (nextPresentedOverlay.hasAttribute('aria-hidden') || nextPresentedOverlay.tagName !== 'ION-TOAST') {
|
|
865
|
+
presentedOverlay.setAttribute('aria-hidden', 'true');
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
/**
|
|
870
|
+
* When dismissing an overlay we need to reveal the new top-most overlay to screen readers.
|
|
871
|
+
* If the top-most overlay is a Toast we potentially need to reveal more overlays since
|
|
872
|
+
* focus is never automatically moved to the Toast.
|
|
873
|
+
*/
|
|
874
|
+
const revealOverlaysToScreenReaders = () => {
|
|
875
|
+
if (doc === undefined)
|
|
876
|
+
return;
|
|
877
|
+
const overlays = getPresentedOverlays(doc);
|
|
878
|
+
for (let i = overlays.length - 1; i >= 0; i--) {
|
|
879
|
+
const currentOverlay = overlays[i];
|
|
880
|
+
/**
|
|
881
|
+
* If the current we are looking at is a Toast then we can remove aria-hidden.
|
|
882
|
+
* However, we potentially need to keep looking at the overlay stack because there
|
|
883
|
+
* could be more Toasts underneath. Additionally, we need to unhide the closest non-Toast
|
|
884
|
+
* overlay too so focus can move there since focus is never automatically moved to the Toast.
|
|
885
|
+
*/
|
|
886
|
+
currentOverlay.removeAttribute('aria-hidden');
|
|
887
|
+
/**
|
|
888
|
+
* If we found a non-Toast element then we can just remove aria-hidden and stop searching entirely
|
|
889
|
+
* since this overlay should always receive focus. As a result, all underlying overlays should still
|
|
890
|
+
* be hidden from screen readers.
|
|
891
|
+
*/
|
|
892
|
+
if (currentOverlay.tagName !== 'ION-TOAST') {
|
|
893
|
+
break;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
};
|
|
805
897
|
export const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
|
package/dist/docs.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"timestamp": "2025-
|
|
2
|
+
"timestamp": "2025-09-03T08:40:22",
|
|
3
3
|
"compiler": {
|
|
4
4
|
"name": "@stencil/core",
|
|
5
5
|
"version": "4.36.2",
|
|
@@ -22566,10 +22566,6 @@
|
|
|
22566
22566
|
"Promise": {
|
|
22567
22567
|
"location": "global",
|
|
22568
22568
|
"id": "global::Promise"
|
|
22569
|
-
},
|
|
22570
|
-
"HTMLElement": {
|
|
22571
|
-
"location": "global",
|
|
22572
|
-
"id": "global::HTMLElement"
|
|
22573
22569
|
}
|
|
22574
22570
|
},
|
|
22575
22571
|
"return": "Promise<boolean>"
|