@ionic/core 8.7.12-dev.11765060985.14ad27fb → 8.7.12-dev.11765231260.1def96ab

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 (63) hide show
  1. package/components/action-sheet.js +186 -5
  2. package/components/ion-select.js +8 -3
  3. package/components/modal.js +16 -86
  4. package/components/overlays.js +11 -15
  5. package/css/core.css +1 -1
  6. package/css/core.css.map +1 -1
  7. package/css/ionic.bundle.css +1 -1
  8. package/css/ionic.bundle.css.map +1 -1
  9. package/dist/cjs/index.cjs.js +1 -1
  10. package/dist/cjs/ion-action-sheet.cjs.entry.js +184 -5
  11. package/dist/cjs/ion-alert.cjs.entry.js +1 -1
  12. package/dist/cjs/ion-datetime_3.cjs.entry.js +1 -1
  13. package/dist/cjs/ion-loading.cjs.entry.js +1 -1
  14. package/dist/cjs/ion-menu_3.cjs.entry.js +1 -1
  15. package/dist/cjs/ion-modal.cjs.entry.js +17 -86
  16. package/dist/cjs/ion-popover.cjs.entry.js +1 -1
  17. package/dist/cjs/ion-select-modal.cjs.entry.js +1 -1
  18. package/dist/cjs/ion-select_3.cjs.entry.js +9 -4
  19. package/dist/cjs/ion-toast.cjs.entry.js +1 -1
  20. package/dist/cjs/ionic.cjs.js +1 -1
  21. package/dist/cjs/loader.cjs.js +1 -1
  22. package/dist/cjs/{overlays-D3xMmZCY.js → overlays-DxIZwUXI.js} +11 -15
  23. package/dist/collection/components/action-sheet/action-sheet.js +199 -4
  24. package/dist/collection/components/modal/modal.js +16 -86
  25. package/dist/collection/components/select/select.js +8 -3
  26. package/dist/collection/utils/overlays.js +11 -15
  27. package/dist/docs.json +14 -8
  28. package/dist/esm/index.js +1 -1
  29. package/dist/esm/ion-action-sheet.entry.js +184 -5
  30. package/dist/esm/ion-alert.entry.js +1 -1
  31. package/dist/esm/ion-datetime_3.entry.js +1 -1
  32. package/dist/esm/ion-loading.entry.js +1 -1
  33. package/dist/esm/ion-menu_3.entry.js +1 -1
  34. package/dist/esm/ion-modal.entry.js +17 -86
  35. package/dist/esm/ion-popover.entry.js +1 -1
  36. package/dist/esm/ion-select-modal.entry.js +1 -1
  37. package/dist/esm/ion-select_3.entry.js +9 -4
  38. package/dist/esm/ion-toast.entry.js +1 -1
  39. package/dist/esm/ionic.js +1 -1
  40. package/dist/esm/loader.js +1 -1
  41. package/dist/esm/{overlays-DYKBVm6h.js → overlays-BymNv-BL.js} +11 -15
  42. package/dist/ionic/index.esm.js +1 -1
  43. package/dist/ionic/ionic.esm.js +1 -1
  44. package/dist/ionic/{p-3fad4ab5.entry.js → p-0b80d700.entry.js} +1 -1
  45. package/dist/ionic/{p-a480563a.entry.js → p-15193d01.entry.js} +1 -1
  46. package/dist/ionic/p-5837f29f.entry.js +4 -0
  47. package/dist/ionic/{p-b4b6513a.entry.js → p-7da39a4d.entry.js} +1 -1
  48. package/dist/ionic/{p-caa8efa1.entry.js → p-83be404e.entry.js} +1 -1
  49. package/dist/ionic/p-8edc7565.entry.js +4 -0
  50. package/dist/ionic/{p-7928cc4d.entry.js → p-98fc09eb.entry.js} +1 -1
  51. package/dist/ionic/p-D87hU-Ly.js +4 -0
  52. package/dist/ionic/p-c69ff6d8.entry.js +4 -0
  53. package/dist/ionic/{p-985f02a8.entry.js → p-cb93126d.entry.js} +1 -1
  54. package/dist/ionic/{p-038f3a87.entry.js → p-e16b69e1.entry.js} +1 -1
  55. package/dist/types/components/action-sheet/action-sheet.d.ts +37 -0
  56. package/dist/types/components/modal/modal.d.ts +0 -13
  57. package/hydrate/index.js +220 -109
  58. package/hydrate/index.mjs +220 -109
  59. package/package.json +4 -1
  60. package/dist/ionic/p-1cf19c5a.entry.js +0 -4
  61. package/dist/ionic/p-9084d52f.entry.js +0 -4
  62. package/dist/ionic/p-CHK505Co.js +0 -4
  63. package/dist/ionic/p-ede27a66.entry.js +0 -4
package/hydrate/index.js CHANGED
@@ -6254,7 +6254,7 @@ const setRootAriaHidden = (hidden = false) => {
6254
6254
  }
6255
6255
  };
6256
6256
  const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts) => {
6257
- var _a, _b, _c;
6257
+ var _a, _b;
6258
6258
  if (overlay.presented) {
6259
6259
  return;
6260
6260
  }
@@ -6288,10 +6288,9 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
6288
6288
  */
6289
6289
  const overlayEl = overlay.el;
6290
6290
  const shouldTrapFocus = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false;
6291
- // Only lock out root content when backdrop is always active. Developers relying on
6292
- // showBackdrop=false or backdropBreakpoint expect background interaction at some point.
6293
- const backdropAlwaysActive = overlayEl.showBackdrop !== false && !(((_a = overlayEl.backdropBreakpoint) !== null && _a !== void 0 ? _a : 0) > 0);
6294
- const shouldLockRoot = shouldTrapFocus && backdropAlwaysActive;
6291
+ // Only lock out root content when backdrop is active. Developers relying on showBackdrop=false
6292
+ // expect background interaction to remain enabled.
6293
+ const shouldLockRoot = shouldTrapFocus && overlayEl.showBackdrop !== false;
6295
6294
  overlay.presented = true;
6296
6295
  overlay.willPresent.emit();
6297
6296
  if (shouldLockRoot) {
@@ -6303,7 +6302,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
6303
6302
  }
6304
6303
  document.body.classList.add(BACKDROP_NO_SCROLL);
6305
6304
  }
6306
- (_b = overlay.willPresentShorthand) === null || _b === void 0 ? void 0 : _b.emit();
6305
+ (_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
6307
6306
  const mode = getIonMode$1(overlay);
6308
6307
  // get the user's animation fn if one was provided
6309
6308
  const animationBuilder = overlay.enterAnimation
@@ -6312,7 +6311,7 @@ const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts)
6312
6311
  const completed = await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
6313
6312
  if (completed) {
6314
6313
  overlay.didPresent.emit();
6315
- (_c = overlay.didPresentShorthand) === null || _c === void 0 ? void 0 : _c.emit();
6314
+ (_b = overlay.didPresentShorthand) === null || _b === void 0 ? void 0 : _b.emit();
6316
6315
  }
6317
6316
  /**
6318
6317
  * If the focused element is already
@@ -6390,7 +6389,7 @@ const restoreElementFocus = async (overlayEl) => {
6390
6389
  }
6391
6390
  };
6392
6391
  const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnimation, opts) => {
6393
- var _a, _b, _c;
6392
+ var _a, _b;
6394
6393
  if (!overlay.presented) {
6395
6394
  return false;
6396
6395
  }
@@ -6406,14 +6405,11 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
6406
6405
  * is dismissed.
6407
6406
  */
6408
6407
  const overlaysLockingRoot = presentedOverlays.filter((o) => {
6409
- var _a;
6410
6408
  const el = o;
6411
- const backdropAlwaysActive = el.showBackdrop !== false && !(((_a = el.backdropBreakpoint) !== null && _a !== void 0 ? _a : 0) > 0);
6412
- return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && backdropAlwaysActive;
6409
+ return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && el.showBackdrop !== false;
6413
6410
  });
6414
6411
  const overlayEl = overlay.el;
6415
- const backdropAlwaysActive = overlayEl.showBackdrop !== false && !(((_a = overlayEl.backdropBreakpoint) !== null && _a !== void 0 ? _a : 0) > 0);
6416
- const locksRoot = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && backdropAlwaysActive;
6412
+ const locksRoot = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && overlayEl.showBackdrop !== false;
6417
6413
  /**
6418
6414
  * If this is the last visible overlay that is trapping focus
6419
6415
  * then we want to re-add the root to the accessibility tree.
@@ -6428,7 +6424,7 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
6428
6424
  // Overlay contents should not be clickable during dismiss
6429
6425
  overlay.el.style.setProperty('pointer-events', 'none');
6430
6426
  overlay.willDismiss.emit({ data, role });
6431
- (_b = overlay.willDismissShorthand) === null || _b === void 0 ? void 0 : _b.emit({ data, role });
6427
+ (_a = overlay.willDismissShorthand) === null || _a === void 0 ? void 0 : _a.emit({ data, role });
6432
6428
  const mode = getIonMode$1(overlay);
6433
6429
  const animationBuilder = overlay.leaveAnimation
6434
6430
  ? overlay.leaveAnimation
@@ -6438,7 +6434,7 @@ const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnim
6438
6434
  await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
6439
6435
  }
6440
6436
  overlay.didDismiss.emit({ data, role });
6441
- (_c = overlay.didDismissShorthand) === null || _c === void 0 ? void 0 : _c.emit({ data, role });
6437
+ (_b = overlay.didDismissShorthand) === null || _b === void 0 ? void 0 : _b.emit({ data, role });
6442
6438
  // Get a reference to all animations currently assigned to this overlay
6443
6439
  // Then tear them down to return the overlay to its initial visual state
6444
6440
  const animations = activeAnimations.get(overlay) || [];
@@ -7617,6 +7613,7 @@ class ActionSheet {
7617
7613
  this.delegateController = createDelegateController(this);
7618
7614
  this.lockController = createLockController();
7619
7615
  this.triggerController = createTriggerController();
7616
+ this.hasRadioButtons = false;
7620
7617
  this.presented = false;
7621
7618
  /** @internal */
7622
7619
  this.hasController = false;
@@ -7661,6 +7658,19 @@ class ActionSheet {
7661
7658
  }
7662
7659
  };
7663
7660
  }
7661
+ buttonsChanged() {
7662
+ const radioButtons = this.getRadioButtons();
7663
+ this.hasRadioButtons = radioButtons.length > 0;
7664
+ // Initialize activeRadioId when buttons change
7665
+ if (this.hasRadioButtons) {
7666
+ const checkedButton = radioButtons.find((b) => { var _a; return ((_a = b.htmlAttributes) === null || _a === void 0 ? void 0 : _a['aria-checked']) === 'true'; });
7667
+ if (checkedButton) {
7668
+ const allButtons = this.getButtons();
7669
+ const checkedIndex = allButtons.indexOf(checkedButton);
7670
+ this.activeRadioId = this.getButtonId(checkedButton, checkedIndex);
7671
+ }
7672
+ }
7673
+ }
7664
7674
  onIsOpenChange(newValue, oldValue) {
7665
7675
  if (newValue === true && oldValue === false) {
7666
7676
  this.present();
@@ -7741,11 +7751,122 @@ class ActionSheet {
7741
7751
  }
7742
7752
  return true;
7743
7753
  }
7754
+ /**
7755
+ * Get all buttons regardless of role.
7756
+ */
7744
7757
  getButtons() {
7745
7758
  return this.buttons.map((b) => {
7746
7759
  return typeof b === 'string' ? { text: b } : b;
7747
7760
  });
7748
7761
  }
7762
+ /**
7763
+ * Get all radio buttons (buttons with role="radio").
7764
+ */
7765
+ getRadioButtons() {
7766
+ return this.getButtons().filter((b) => {
7767
+ var _a;
7768
+ const role = (_a = b.htmlAttributes) === null || _a === void 0 ? void 0 : _a.role;
7769
+ return role === 'radio' && !isCancel(role);
7770
+ });
7771
+ }
7772
+ /**
7773
+ * Handle radio button selection and update aria-checked state.
7774
+ *
7775
+ * @param button The radio button that was selected.
7776
+ */
7777
+ selectRadioButton(button) {
7778
+ const buttonId = this.getButtonId(button);
7779
+ // Set the active radio ID (this will trigger a re-render and update aria-checked)
7780
+ this.activeRadioId = buttonId;
7781
+ }
7782
+ /**
7783
+ * Get or generate an ID for a button.
7784
+ *
7785
+ * @param button The button for which to get the ID.
7786
+ * @param index Optional index of the button in the buttons array.
7787
+ * @returns The ID of the button.
7788
+ */
7789
+ getButtonId(button, index) {
7790
+ if (button.id) {
7791
+ return button.id;
7792
+ }
7793
+ const allButtons = this.getButtons();
7794
+ const buttonIndex = index !== undefined ? index : allButtons.indexOf(button);
7795
+ return `action-sheet-button-${this.overlayIndex}-${buttonIndex}`;
7796
+ }
7797
+ /**
7798
+ * When the action sheet has radio buttons, we want to follow the
7799
+ * keyboard navigation pattern for radio groups:
7800
+ * - Arrow Down/Right: Move to the next radio button (wrap to first if at end)
7801
+ * - Arrow Up/Left: Move to the previous radio button (wrap to last if at start)
7802
+ * - Space/Enter: Select the focused radio button and trigger its handler
7803
+ */
7804
+ onKeydown(ev) {
7805
+ // Only handle keyboard navigation if we have radio buttons
7806
+ if (!this.hasRadioButtons || !this.presented) {
7807
+ return;
7808
+ }
7809
+ const target = ev.target;
7810
+ // Ignore if the target element is not within the action sheet or not a radio button
7811
+ if (!this.el.contains(target) ||
7812
+ !target.classList.contains('action-sheet-button') ||
7813
+ target.getAttribute('role') !== 'radio') {
7814
+ return;
7815
+ }
7816
+ // Get all radio button elements and filter out disabled ones
7817
+ const radios = Array.from(this.el.querySelectorAll('.action-sheet-button[role="radio"]')).filter((el) => !el.disabled);
7818
+ const currentIndex = radios.findIndex((radio) => radio.id === target.id);
7819
+ if (currentIndex === -1) {
7820
+ return;
7821
+ }
7822
+ const allButtons = this.getButtons();
7823
+ const radioButtons = this.getRadioButtons();
7824
+ /**
7825
+ * Build a map of button element IDs to their ActionSheetButton
7826
+ * config objects.
7827
+ * This allows us to quickly look up which button config corresponds
7828
+ * to a DOM element when handling keyboard navigation
7829
+ * (e.g., whenuser presses Space/Enter or arrow keys).
7830
+ * The key is the ID that was set on the DOM element during render,
7831
+ * and the value is the ActionSheetButton config that contains the
7832
+ * handler and other properties.
7833
+ */
7834
+ const buttonIdMap = new Map();
7835
+ radioButtons.forEach((b) => {
7836
+ const allIndex = allButtons.indexOf(b);
7837
+ const buttonId = this.getButtonId(b, allIndex);
7838
+ buttonIdMap.set(buttonId, b);
7839
+ });
7840
+ let nextEl;
7841
+ if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
7842
+ ev.preventDefault();
7843
+ ev.stopPropagation();
7844
+ nextEl = currentIndex === radios.length - 1 ? radios[0] : radios[currentIndex + 1];
7845
+ }
7846
+ else if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
7847
+ ev.preventDefault();
7848
+ ev.stopPropagation();
7849
+ nextEl = currentIndex === 0 ? radios[radios.length - 1] : radios[currentIndex - 1];
7850
+ }
7851
+ else if (ev.key === ' ' || ev.key === 'Enter') {
7852
+ ev.preventDefault();
7853
+ ev.stopPropagation();
7854
+ const button = buttonIdMap.get(target.id);
7855
+ if (button) {
7856
+ this.selectRadioButton(button);
7857
+ this.buttonClick(button);
7858
+ }
7859
+ return;
7860
+ }
7861
+ // Focus the next radio button
7862
+ if (nextEl) {
7863
+ const button = buttonIdMap.get(nextEl.id);
7864
+ if (button) {
7865
+ this.selectRadioButton(button);
7866
+ nextEl.focus();
7867
+ }
7868
+ }
7869
+ }
7749
7870
  connectedCallback() {
7750
7871
  prepareOverlay(this.el);
7751
7872
  this.triggerChanged();
@@ -7762,6 +7883,8 @@ class ActionSheet {
7762
7883
  if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
7763
7884
  setOverlayId(this.el);
7764
7885
  }
7886
+ // Initialize activeRadioId for radio buttons
7887
+ this.buttonsChanged();
7765
7888
  }
7766
7889
  componentDidLoad() {
7767
7890
  /**
@@ -7799,22 +7922,74 @@ class ActionSheet {
7799
7922
  */
7800
7923
  this.triggerChanged();
7801
7924
  }
7925
+ renderActionSheetButtons(filteredButtons) {
7926
+ const mode = getIonMode$1(this);
7927
+ const { activeRadioId } = this;
7928
+ return filteredButtons.map((b, index) => {
7929
+ var _a;
7930
+ const isRadio = ((_a = b.htmlAttributes) === null || _a === void 0 ? void 0 : _a.role) === 'radio';
7931
+ const buttonId = this.getButtonId(b, index);
7932
+ const radioButtons = this.getRadioButtons();
7933
+ const isActiveRadio = isRadio && buttonId === activeRadioId;
7934
+ const isFirstRadio = isRadio && b === radioButtons[0];
7935
+ // For radio buttons, set tabindex: 0 for the active one, -1 for others
7936
+ // For non-radio buttons, use default tabindex (undefined, which means 0)
7937
+ /**
7938
+ * For radio buttons, set tabindex based on activeRadioId
7939
+ * - If the button is the active radio, tabindex is 0
7940
+ * - If no radio is active, the first radio button should have tabindex 0
7941
+ * - All other radio buttons have tabindex -1
7942
+ * For non-radio buttons, use default tabindex (undefined, which means 0)
7943
+ */
7944
+ let tabIndex;
7945
+ if (isRadio) {
7946
+ // Focus on the active radio button
7947
+ if (isActiveRadio) {
7948
+ tabIndex = 0;
7949
+ }
7950
+ else if (!activeRadioId && isFirstRadio) {
7951
+ // No active radio, first radio gets focus
7952
+ tabIndex = 0;
7953
+ }
7954
+ else {
7955
+ // All other radios are not focusable
7956
+ tabIndex = -1;
7957
+ }
7958
+ }
7959
+ else {
7960
+ tabIndex = undefined;
7961
+ }
7962
+ // For radio buttons, set aria-checked based on activeRadioId
7963
+ // Otherwise, use the value from htmlAttributes if provided
7964
+ const htmlAttrs = Object.assign({}, b.htmlAttributes);
7965
+ if (isRadio) {
7966
+ htmlAttrs['aria-checked'] = isActiveRadio ? 'true' : 'false';
7967
+ }
7968
+ return (hAsync("button", Object.assign({}, htmlAttrs, { role: isRadio ? 'radio' : undefined, type: "button", id: buttonId, class: Object.assign(Object.assign({}, buttonClass$3(b)), { 'action-sheet-selected': isActiveRadio }), onClick: () => {
7969
+ if (isRadio) {
7970
+ this.selectRadioButton(b);
7971
+ }
7972
+ this.buttonClick(b);
7973
+ }, disabled: b.disabled, tabIndex: tabIndex }), hAsync("span", { class: "action-sheet-button-inner" }, b.icon && hAsync("ion-icon", { icon: b.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" }), b.text), mode === 'md' && hAsync("ion-ripple-effect", null)));
7974
+ });
7975
+ }
7802
7976
  render() {
7803
- const { header, htmlAttributes, overlayIndex } = this;
7977
+ const { header, htmlAttributes, overlayIndex, hasRadioButtons } = this;
7804
7978
  const mode = getIonMode$1(this);
7805
7979
  const allButtons = this.getButtons();
7806
7980
  const cancelButton = allButtons.find((b) => b.role === 'cancel');
7807
7981
  const buttons = allButtons.filter((b) => b.role !== 'cancel');
7808
7982
  const headerID = `action-sheet-${overlayIndex}-header`;
7809
- return (hAsync(Host, Object.assign({ key: '9fef156b2a1f09ca4a6c1fe1f37c374139bde03c', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1" }, htmlAttributes, { style: {
7983
+ return (hAsync(Host, Object.assign({ key: '173fcff5b1da7c33c267de4667591c946b8c8d03', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1" }, htmlAttributes, { style: {
7810
7984
  zIndex: `${20000 + this.overlayIndex}`,
7811
- }, class: Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'action-sheet-translucent': this.translucent }), onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), hAsync("ion-backdrop", { key: '81cf3f7d19864e041813987b46d2d115b8466819', tappable: this.backdropDismiss }), hAsync("div", { key: '791c6a976683646fc306a42c15c5078b6f06a45f', tabindex: "0", "aria-hidden": "true" }), hAsync("div", { key: 'a350b489ef7852eab9dc2227ce6d92da27dd9bf9', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, hAsync("div", { key: '69ba51ee13510c1a411d87cb4845b11b7302a36f', class: "action-sheet-container" }, hAsync("div", { key: 'bded15b8306c36591e526f0f99e1eeabcbab3915', class: "action-sheet-group", ref: (el) => (this.groupEl = el) }, header !== undefined && (hAsync("div", { key: '06b5147c0f6d9180fe8f12e75c9b4a0310226adc', id: headerID, class: {
7985
+ }, class: Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'action-sheet-translucent': this.translucent }), onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), hAsync("ion-backdrop", { key: '521ede659f747864f6c974e09016436eceb7158c', tappable: this.backdropDismiss }), hAsync("div", { key: '7a7946fc434bc444f16a70638f5e948c69d33fcd', tabindex: "0", "aria-hidden": "true" }), hAsync("div", { key: 'bcff39a580489dbafa255842e57aa8602c6d0f18', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, hAsync("div", { key: '84bba13ce14261f0f0daa3f9c77648c9e7f36e0e', class: "action-sheet-container" }, hAsync("div", { key: 'd9c8ac404fd6719a7adf8cb36549f67616f9a0c4', class: "action-sheet-group", ref: (el) => (this.groupEl = el), role: hasRadioButtons ? 'radiogroup' : undefined }, header !== undefined && (hAsync("div", { key: '180433a8ad03ef5c54728a1a8f34715b6921d658', id: headerID, class: {
7812
7986
  'action-sheet-title': true,
7813
7987
  'action-sheet-has-sub-title': this.subHeader !== undefined,
7814
- } }, header, this.subHeader && hAsync("div", { key: '54874362a75c679aba803bf4f8768f5404d2dd28', class: "action-sheet-sub-title" }, this.subHeader))), buttons.map((b) => (hAsync("button", Object.assign({}, b.htmlAttributes, { type: "button", id: b.id, class: buttonClass$3(b), onClick: () => this.buttonClick(b), disabled: b.disabled }), hAsync("span", { class: "action-sheet-button-inner" }, b.icon && hAsync("ion-icon", { icon: b.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" }), b.text), mode === 'md' && hAsync("ion-ripple-effect", null))))), cancelButton && (hAsync("div", { key: '67b0de298eb424f3dea846a841b7a06d70e3930d', class: "action-sheet-group action-sheet-group-cancel" }, hAsync("button", Object.assign({ key: 'e7e3f9a5495eea9b97dbf885ef36944f2e420eff' }, cancelButton.htmlAttributes, { type: "button", class: buttonClass$3(cancelButton), onClick: () => this.buttonClick(cancelButton) }), hAsync("span", { key: 'f889d29ed6c3d14bbc1d805888351d87f5122377', class: "action-sheet-button-inner" }, cancelButton.icon && (hAsync("ion-icon", { key: '7c05cf424b38c37fd40aaeb42a494387291571fb', icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && hAsync("ion-ripple-effect", { key: 'bed927b477dc2708a5123ef560274fca9819b3d6' })))))), hAsync("div", { key: 'c5df1b11dc15a93892d57065d3dd5fbe02e43b39', tabindex: "0", "aria-hidden": "true" })));
7988
+ } }, header, this.subHeader && hAsync("div", { key: '7138e79e61b1a8f42bc5a9175c57fa2f15d7ec5a', class: "action-sheet-sub-title" }, this.subHeader))), this.renderActionSheetButtons(buttons)), cancelButton && (hAsync("div", { key: 'b617c722f5b8028d73ed34b69310f312c65f34a7', class: "action-sheet-group action-sheet-group-cancel" }, hAsync("button", Object.assign({ key: 'd0dd876fc48815df3710413c201c0b445a8e16c0' }, cancelButton.htmlAttributes, { type: "button", class: buttonClass$3(cancelButton), onClick: () => this.buttonClick(cancelButton) }), hAsync("span", { key: 'e7b960157cc6fc5fe92a12090b2be55e8ae072e4', class: "action-sheet-button-inner" }, cancelButton.icon && (hAsync("ion-icon", { key: '05498ffc60cab911dbff0ecbc6168dea59ada9a5', icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && hAsync("ion-ripple-effect", { key: '3d401346cea301be4ca03671f7370f6f4b0b6bde' })))))), hAsync("div", { key: '971f3c5fcc07f36c28eb469a47ec0290c692e139', tabindex: "0", "aria-hidden": "true" })));
7815
7989
  }
7816
7990
  get el() { return getElement(this); }
7817
7991
  static get watchers() { return {
7992
+ "buttons": ["buttonsChanged"],
7818
7993
  "isOpen": ["onIsOpenChange"],
7819
7994
  "trigger": ["triggerChanged"]
7820
7995
  }; }
@@ -7842,12 +8017,13 @@ class ActionSheet {
7842
8017
  "htmlAttributes": [16],
7843
8018
  "isOpen": [4, "is-open"],
7844
8019
  "trigger": [1],
8020
+ "activeRadioId": [32],
7845
8021
  "present": [64],
7846
8022
  "dismiss": [64],
7847
8023
  "onDidDismiss": [64],
7848
8024
  "onWillDismiss": [64]
7849
8025
  },
7850
- "$listeners$": undefined,
8026
+ "$listeners$": [[0, "keydown", "onKeydown"]],
7851
8027
  "$lazyBundleId$": "-",
7852
8028
  "$attrsToReflect$": []
7853
8029
  }; }
@@ -23019,13 +23195,7 @@ class Modal {
23019
23195
  };
23020
23196
  window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
23021
23197
  }
23022
- /**
23023
- * Recalculate isSheetModal because framework bindings (e.g., Angular)
23024
- * may not have been applied when componentWillLoad ran.
23025
- */
23026
- const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
23027
- this.isSheetModal = isSheetModal;
23028
- if (isSheetModal) {
23198
+ if (this.isSheetModal) {
23029
23199
  this.initSheetGesture();
23030
23200
  }
23031
23201
  else if (hasCardModal) {
@@ -23107,79 +23277,6 @@ class Modal {
23107
23277
  this.gesture = gesture;
23108
23278
  this.moveSheetToBreakpoint = moveSheetToBreakpoint;
23109
23279
  this.gesture.enable(true);
23110
- /**
23111
- * When backdrop interaction is allowed, nested router outlets from child routes
23112
- * may block pointer events to parent content. Apply passthrough styles only when
23113
- * the modal was the sole content of a child route page.
23114
- * See https://github.com/ionic-team/ionic-framework/issues/30700
23115
- */
23116
- const backdropNotBlocking = this.showBackdrop === false || this.focusTrap === false || backdropBreakpoint > 0;
23117
- if (backdropNotBlocking) {
23118
- this.setupChildRoutePassthrough();
23119
- }
23120
- }
23121
- /**
23122
- * For sheet modals that allow background interaction, sets up pointer-events
23123
- * passthrough on child route page wrappers and nested router outlets.
23124
- */
23125
- setupChildRoutePassthrough() {
23126
- var _a;
23127
- const pageParent = this.getOriginalPageParent();
23128
- // Skip ion-app (controller modals) and pages with other content (inline modals)
23129
- if (!pageParent || pageParent.tagName === 'ION-APP') {
23130
- return;
23131
- }
23132
- const hasVisibleContent = Array.from(pageParent.children).some((child) => {
23133
- var _a;
23134
- if (child === this.el)
23135
- return false;
23136
- if (child instanceof HTMLElement && window.getComputedStyle(child).display === 'none')
23137
- return false;
23138
- if (child.tagName === 'TEMPLATE' || child.tagName === 'SLOT')
23139
- return false;
23140
- if (child.nodeType === Node.TEXT_NODE && !((_a = child.textContent) === null || _a === void 0 ? void 0 : _a.trim()))
23141
- return false;
23142
- return true;
23143
- });
23144
- if (hasVisibleContent) {
23145
- return;
23146
- }
23147
- // Child route case: page only contained the modal
23148
- pageParent.classList.add('ion-page-overlay-passthrough');
23149
- // Also make nested router outlets passthrough
23150
- const routerOutlet = pageParent.parentElement;
23151
- if ((routerOutlet === null || routerOutlet === void 0 ? void 0 : routerOutlet.tagName) === 'ION-ROUTER-OUTLET' && ((_a = routerOutlet.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) !== 'ION-APP') {
23152
- routerOutlet.style.setProperty('pointer-events', 'none');
23153
- routerOutlet.setAttribute('data-overlay-passthrough', 'true');
23154
- }
23155
- }
23156
- /**
23157
- * Finds the ion-page ancestor of the modal's original parent location.
23158
- */
23159
- getOriginalPageParent() {
23160
- if (!this.cachedOriginalParent) {
23161
- return null;
23162
- }
23163
- let pageParent = this.cachedOriginalParent;
23164
- while (pageParent && !pageParent.classList.contains('ion-page')) {
23165
- pageParent = pageParent.parentElement;
23166
- }
23167
- return pageParent;
23168
- }
23169
- /**
23170
- * Removes passthrough styles added by setupChildRoutePassthrough.
23171
- */
23172
- cleanupChildRoutePassthrough() {
23173
- const pageParent = this.getOriginalPageParent();
23174
- if (!pageParent) {
23175
- return;
23176
- }
23177
- pageParent.classList.remove('ion-page-overlay-passthrough');
23178
- const routerOutlet = pageParent.parentElement;
23179
- if (routerOutlet === null || routerOutlet === void 0 ? void 0 : routerOutlet.hasAttribute('data-overlay-passthrough')) {
23180
- routerOutlet.style.removeProperty('pointer-events');
23181
- routerOutlet.removeAttribute('data-overlay-passthrough');
23182
- }
23183
23280
  }
23184
23281
  sheetOnDismiss() {
23185
23282
  /**
@@ -23269,7 +23366,6 @@ class Modal {
23269
23366
  }
23270
23367
  this.cleanupViewTransitionListener();
23271
23368
  this.cleanupParentRemovalObserver();
23272
- this.cleanupChildRoutePassthrough();
23273
23369
  }
23274
23370
  this.currentBreakpoint = undefined;
23275
23371
  this.animation = undefined;
@@ -23466,6 +23562,17 @@ class Modal {
23466
23562
  this.cachedOriginalParent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
23467
23563
  return;
23468
23564
  }
23565
+ /**
23566
+ * Don't observe for controller-based modals or when the parent is the
23567
+ * app root (document.body or ion-app). These parents won't be removed,
23568
+ * and observing document.body with subtree: true causes performance
23569
+ * issues with frameworks like Angular during change detection.
23570
+ */
23571
+ if (this.hasController ||
23572
+ this.cachedOriginalParent === document.body ||
23573
+ this.cachedOriginalParent.tagName === 'ION-APP') {
23574
+ return;
23575
+ }
23469
23576
  this.parentRemovalObserver = new MutationObserver((mutations) => {
23470
23577
  mutations.forEach((mutation) => {
23471
23578
  if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
@@ -23507,20 +23614,20 @@ class Modal {
23507
23614
  const isCardModal = presentingElement !== undefined && mode === 'ios';
23508
23615
  const isHandleCycle = handleBehavior === 'cycle';
23509
23616
  const isSheetModalWithHandle = isSheetModal && showHandle;
23510
- return (hAsync(Host, Object.assign({ key: '880d34a27983dde27c81a06bfed390bf38e43244', "no-router": true,
23617
+ return (hAsync(Host, Object.assign({ key: '5d8261a1a174d83642c0f7f2aa4f6c265f50fa57', "no-router": true,
23511
23618
  // Allow the modal to be navigable when the handle is focusable
23512
23619
  tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
23513
23620
  zIndex: `${20000 + this.overlayIndex}`,
23514
- }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), hAsync("ion-backdrop", { key: 'c674d142ace2b3e5bd38b302cf2984fc3fac11c8', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && hAsync("div", { key: 'ce83713b57960d354935ef8e65251892ed9d4e3b', class: "modal-shadow" }), hAsync("div", Object.assign({ key: '67c001e824f5c31eb58053eea71c884817479896',
23621
+ }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), hAsync("ion-backdrop", { key: 'bc165dd344e752c13076ca5ae37ea7d68d618d55', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && hAsync("div", { key: '4a2f6edaeeec2978f0cd7b2b93a44c2f0da3ab54', class: "modal-shadow" }), hAsync("div", Object.assign({ key: '13d662aa50871e97567270dbbce6825633c62bad',
23515
23622
  /*
23516
23623
  role and aria-modal must be used on the
23517
23624
  same element. They must also be set inside the
23518
23625
  shadow DOM otherwise ion-button will not be highlighted
23519
23626
  when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
23520
23627
  */
23521
- role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (hAsync("button", { key: '9263cbb0c5f550ef463b72446c21379ccaf0ccdd', class: "modal-handle",
23628
+ role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (hAsync("button", { key: 'e678cd3c64a0ab56636f68f9fa416741589f783c', class: "modal-handle",
23522
23629
  // Prevents the handle from receiving keyboard focus when it does not cycle
23523
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), hAsync("slot", { key: '3ef07e617f2b1d46fca6a00b40119c35bff4215a', onSlotchange: this.onSlotChange }))));
23630
+ tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), hAsync("slot", { key: '1ebc3549c5c67ea286384b9917ed4dd8958ea2ae', onSlotchange: this.onSlotChange }))));
23524
23631
  }
23525
23632
  get el() { return getElement(this); }
23526
23633
  static get watchers() { return {
@@ -23560,7 +23667,6 @@ class Modal {
23560
23667
  "keepContentsMounted": [4, "keep-contents-mounted"],
23561
23668
  "focusTrap": [4, "focus-trap"],
23562
23669
  "canDismiss": [4, "can-dismiss"],
23563
- "isSheetModal": [32],
23564
23670
  "presented": [32],
23565
23671
  "present": [64],
23566
23672
  "dismiss": [64],
@@ -33709,13 +33815,18 @@ class Select {
33709
33815
  .filter((cls) => cls !== 'hydrated')
33710
33816
  .join(' ');
33711
33817
  const optClass = `${OPTION_CLASS} ${copyClasses}`;
33818
+ const isSelected = isOptionSelected(selectValue, value, this.compareWith);
33712
33819
  return {
33713
- role: isOptionSelected(selectValue, value, this.compareWith) ? 'selected' : '',
33820
+ role: isSelected ? 'selected' : '',
33714
33821
  text: option.textContent,
33715
33822
  cssClass: optClass,
33716
33823
  handler: () => {
33717
33824
  this.setValue(value);
33718
33825
  },
33826
+ htmlAttributes: {
33827
+ 'aria-checked': isSelected ? 'true' : 'false',
33828
+ role: 'radio',
33829
+ },
33719
33830
  };
33720
33831
  });
33721
33832
  // Add "cancel" button
@@ -34096,7 +34207,7 @@ class Select {
34096
34207
  * TODO(FW-5592): Remove hasStartEndSlots condition
34097
34208
  */
34098
34209
  const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || isExpanded || hasStartEndSlots));
34099
- return (hAsync(Host, { key: '35b5e18e6f79a802ff2d46d1242e80ff755cc0b9', onClick: this.onClick, class: createColorClasses$1(this.color, {
34210
+ return (hAsync(Host, { key: 'd8026835993d0e6dce747098f741a06ae4e4f54d', onClick: this.onClick, class: createColorClasses$1(this.color, {
34100
34211
  [mode]: true,
34101
34212
  'in-item': inItem,
34102
34213
  'in-item-color': hostContext('ion-item.ion-color', el),
@@ -34114,7 +34225,7 @@ class Select {
34114
34225
  [`select-justify-${justify}`]: justifyEnabled,
34115
34226
  [`select-shape-${shape}`]: shape !== undefined,
34116
34227
  [`select-label-placement-${labelPlacement}`]: true,
34117
- }) }, hAsync("label", { key: '6005b34a0c50bc4d7653a4276bc232ecd02e083c', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'c7e07aa81ae856c057f16275dd058f37c5670a47', class: "select-wrapper-inner" }, hAsync("slot", { key: '7fc2deefe0424404caacdbbd9e08ed43ba55d28a', name: "start" }), hAsync("div", { key: '157d74ee717b1bc30b5f1c233a09b0c8456aa68e', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), hAsync("slot", { key: 'ea66db304528b82bf9317730b6dce3db2612f235', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && hAsync("div", { key: '786eb1530b7476f0615d4e7c0bf4e7e4dc66509c', class: "select-highlight" })), this.renderBottomContent()));
34228
+ }) }, hAsync("label", { key: 'fcfb40209d6d07d49c7fdca4884b31abf6ac2567', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'f191664f2290c3890bde1156157c83a6ff17dbe2', class: "select-wrapper-inner" }, hAsync("slot", { key: '317a28d1115b4214f291e228ce0fe6fc782e57d5', name: "start" }), hAsync("div", { key: 'db68e18abd5ca3a1023d7c7b58bf89893ae18073', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), hAsync("slot", { key: '4274e042267c2234a198b0f65c89477898d08130', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && hAsync("div", { key: '2e2eb1ee2b2791e0683d9afb186fde6e938ca59c', class: "select-highlight" })), this.renderBottomContent()));
34118
34229
  }
34119
34230
  get el() { return getElement(this); }
34120
34231
  static get watchers() { return {