@ionic/core 8.5.8-dev.11748364689.107665ad → 8.5.8-dev.11748388365.11ad9dfe

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/button.js +23 -5
  2. package/components/ion-datetime.js +27 -51
  3. package/components/ion-input-password-toggle.js +2 -2
  4. package/components/ion-searchbar.js +4 -4
  5. package/components/modal.js +157 -58
  6. package/components/picker-column2.js +3 -3
  7. package/dist/cjs/ion-button_2.cjs.entry.js +19 -3
  8. package/dist/cjs/ion-datetime_3.cjs.entry.js +30 -54
  9. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +2 -2
  10. package/dist/cjs/ion-modal.cjs.entry.js +157 -58
  11. package/dist/cjs/ion-searchbar.cjs.entry.js +4 -4
  12. package/dist/cjs/ionic.cjs.js +1 -1
  13. package/dist/cjs/loader.cjs.js +1 -1
  14. package/dist/collection/components/button/button.js +23 -3
  15. package/dist/collection/components/datetime/datetime.js +27 -51
  16. package/dist/collection/components/input-password-toggle/input-password-toggle.js +2 -2
  17. package/dist/collection/components/modal/animations/ios.enter.js +41 -1
  18. package/dist/collection/components/modal/animations/ios.leave.js +24 -2
  19. package/dist/collection/components/modal/animations/md.enter.js +41 -1
  20. package/dist/collection/components/modal/animations/md.leave.js +24 -2
  21. package/dist/collection/components/modal/gestures/sheet.js +27 -52
  22. package/dist/collection/components/picker-legacy-column/picker-column.js +3 -3
  23. package/dist/collection/components/searchbar/searchbar.js +5 -5
  24. package/dist/docs.json +2 -2
  25. package/dist/esm/ion-button_2.entry.js +20 -4
  26. package/dist/esm/ion-datetime_3.entry.js +30 -54
  27. package/dist/esm/ion-input-password-toggle.entry.js +2 -2
  28. package/dist/esm/ion-modal.entry.js +157 -58
  29. package/dist/esm/ion-searchbar.entry.js +4 -4
  30. package/dist/esm/ionic.js +1 -1
  31. package/dist/esm/loader.js +1 -1
  32. package/dist/esm-es5/ion-button_2.entry.js +1 -1
  33. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  34. package/dist/esm-es5/ion-input-password-toggle.entry.js +1 -1
  35. package/dist/esm-es5/ion-modal.entry.js +1 -1
  36. package/dist/esm-es5/ion-searchbar.entry.js +1 -1
  37. package/dist/esm-es5/ionic.js +1 -1
  38. package/dist/esm-es5/loader.js +1 -1
  39. package/dist/html.html-data.json +1 -1
  40. package/dist/ionic/ionic.esm.js +1 -1
  41. package/dist/ionic/p-12914457.entry.js +4 -0
  42. package/dist/ionic/{p-50cb2e8b.system.entry.js → p-3cee5d7c.system.entry.js} +2 -2
  43. package/dist/ionic/p-3d2b2787.system.entry.js +4 -0
  44. package/dist/ionic/{p-7611ede3.system.entry.js → p-3ec227cd.system.entry.js} +1 -1
  45. package/dist/ionic/p-4090ce24.entry.js +4 -0
  46. package/dist/ionic/p-8b8b4530.system.entry.js +4 -0
  47. package/dist/ionic/p-94a18d00.entry.js +4 -0
  48. package/dist/ionic/p-cec902a0.system.entry.js +4 -0
  49. package/dist/ionic/{p-891553d8.entry.js → p-e7f732ef.entry.js} +1 -1
  50. package/dist/ionic/p-f725bf9e.system.js +2 -2
  51. package/dist/ionic/{p-a835aca8.entry.js → p-ffa2125f.entry.js} +1 -1
  52. package/dist/types/components/button/button.d.ts +11 -0
  53. package/dist/types/components/searchbar/searchbar.d.ts +1 -1
  54. package/dist/types/components.d.ts +2 -2
  55. package/hydrate/index.js +211 -121
  56. package/hydrate/index.mjs +211 -121
  57. package/package.json +2 -2
  58. package/dist/ionic/p-451706f5.entry.js +0 -4
  59. package/dist/ionic/p-57957c0f.entry.js +0 -4
  60. package/dist/ionic/p-6b8530f5.system.entry.js +0 -4
  61. package/dist/ionic/p-b5432d15.entry.js +0 -4
  62. package/dist/ionic/p-c1b7d311.system.entry.js +0 -4
  63. package/dist/ionic/p-c8731f25.system.entry.js +0 -4
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
4
+ import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, h, Host } from '@stencil/core/internal/client';
5
5
  import { h as hasShadowDom, i as inheritAriaAttributes } from './helpers.js';
6
6
  import { a as printIonWarning } from './index4.js';
7
7
  import { o as openURL, c as createColorClasses, h as hostContext } from './theme.js';
@@ -77,6 +77,20 @@ const Button = /*@__PURE__*/ proxyCustomElement(class Button extends HTMLElement
77
77
  this.formButtonEl.disabled = disabled;
78
78
  }
79
79
  }
80
+ /**
81
+ * This component is used within the `ion-input-password-toggle` component
82
+ * to toggle the visibility of the password input.
83
+ * These attributes need to update based on the state of the password input.
84
+ * Otherwise, the values will be stale.
85
+ *
86
+ * @param newValue
87
+ * @param _oldValue
88
+ * @param propName
89
+ */
90
+ onAriaChanged(newValue, _oldValue, propName) {
91
+ this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { [propName]: newValue });
92
+ forceUpdate(this);
93
+ }
80
94
  /**
81
95
  * This is responsible for rendering a hidden native
82
96
  * button element inside the associated form. This allows
@@ -214,7 +228,7 @@ const Button = /*@__PURE__*/ proxyCustomElement(class Button extends HTMLElement
214
228
  {
215
229
  type !== 'button' && this.renderHiddenButton();
216
230
  }
217
- return (h(Host, { key: 'e213b0bb76b3f90f883b1a0ea463bb86c2df69c3', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses(color, {
231
+ return (h(Host, { key: 'b105ad09215adb3ca2298acdadf0dc9154bbb9b0', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses(color, {
218
232
  [mode]: true,
219
233
  [buttonType]: true,
220
234
  [`${buttonType}-${expand}`]: expand !== undefined,
@@ -229,11 +243,13 @@ const Button = /*@__PURE__*/ proxyCustomElement(class Button extends HTMLElement
229
243
  'button-disabled': disabled,
230
244
  'ion-activatable': true,
231
245
  'ion-focusable': true,
232
- }) }, h(TagType, Object.assign({ key: 'b7c2a46fb994024841219316f4089335fa463d84' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), h("span", { key: '3e07a5c9f86836f9fbaefc6c617bdde6eb6f70cd', class: "button-inner" }, h("slot", { key: '41c08ae09aed16faaa57707d229ff75d97f0731c', name: "icon-only", onSlotchange: this.slotChanged }), h("slot", { key: 'ab8b749e4572884cc04970a7594466b4a24c886e', name: "start" }), h("slot", { key: '397f7ff48ea45e82029414be95d29ae86e12c3a9' }), h("slot", { key: '9a5627713002e8be3738d392b616f6e951b70e12', name: "end" })), mode === 'md' && h("ion-ripple-effect", { key: '105566543ceda102474edab7ca8a44c7e71af589', type: this.rippleType }))));
246
+ }) }, h(TagType, Object.assign({ key: '66b4e7112bcb9e41d5a723fbbadb0a3104f9ee1d' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), h("span", { key: '1439fc3da280221028dcf7ce8ec9dab273c4d4bb', class: "button-inner" }, h("slot", { key: 'd5269ae1afc87ec7b99746032f59cbae93720a9f', name: "icon-only", onSlotchange: this.slotChanged }), h("slot", { key: '461c83e97aa246aa86d83e14f1e15a288d35041e', name: "start" }), h("slot", { key: '807170d47101f9f6a333dd4ff489c89284f306fe' }), h("slot", { key: 'e67f116dd0349a0d27893e4f3ff0ccef1d402f80', name: "end" })), mode === 'md' && h("ion-ripple-effect", { key: '273f0bd9645a36c1bfd18a5c2ab4f81e22b7b989', type: this.rippleType }))));
233
247
  }
234
248
  get el() { return this; }
235
249
  static get watchers() { return {
236
- "disabled": ["disabledChanged"]
250
+ "disabled": ["disabledChanged"],
251
+ "aria-checked": ["onAriaChanged"],
252
+ "aria-label": ["onAriaChanged"]
237
253
  }; }
238
254
  static get style() { return {
239
255
  ios: IonButtonIosStyle0,
@@ -258,7 +274,9 @@ const Button = /*@__PURE__*/ proxyCustomElement(class Button extends HTMLElement
258
274
  "form": [1],
259
275
  "isCircle": [32]
260
276
  }, undefined, {
261
- "disabled": ["disabledChanged"]
277
+ "disabled": ["disabledChanged"],
278
+ "aria-checked": ["onAriaChanged"],
279
+ "aria-label": ["onAriaChanged"]
262
280
  }]);
263
281
  function defineCustomElement() {
264
282
  if (typeof customElements === "undefined") {
@@ -685,19 +685,18 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
685
685
  warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
686
686
  }
687
687
  /**
688
- * If there are multiple values, pick an arbitrary one to clamp to. This way,
689
- * if the values are across months, we always show at least one of them. Note
690
- * that the values don't necessarily have to be in order.
688
+ * If there are multiple values, clamp to the last one.
689
+ * This is because the last value is the one that the user
690
+ * has most recently interacted with.
691
691
  */
692
- const singleValue = Array.isArray(valueToProcess) ? valueToProcess[0] : valueToProcess;
692
+ const singleValue = Array.isArray(valueToProcess) ? valueToProcess[valueToProcess.length - 1] : valueToProcess;
693
693
  const targetValue = clampDate(singleValue, minParts, maxParts);
694
694
  const { month, day, year, hour, minute } = targetValue;
695
695
  const ampm = parseAmPm(hour);
696
696
  /**
697
- * Since `activeParts` indicates a value that
698
- * been explicitly selected either by the
699
- * user or the app, only update `activeParts`
700
- * if the `value` property is set.
697
+ * Since `activeParts` indicates a value that been explicitly selected
698
+ * either by the user or the app, only update `activeParts` if the
699
+ * `value` property is set.
701
700
  */
702
701
  if (hasValue) {
703
702
  if (Array.isArray(valueToProcess)) {
@@ -722,51 +721,28 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
722
721
  */
723
722
  this.activeParts = [];
724
723
  }
725
- /**
726
- * Only animate if:
727
- * 1. We're using grid style (wheel style pickers should just jump to new value)
728
- * 2. The month and/or year actually changed, and both are defined (otherwise there's nothing to animate to)
729
- * 3. The calendar body is visible (prevents animation when in collapsed datetime-button, for example)
730
- * 4. The month/year picker is not open (since you wouldn't see the animation anyway)
731
- */
732
724
  const didChangeMonth = (month !== undefined && month !== workingParts.month) || (year !== undefined && year !== workingParts.year);
733
725
  const bodyIsVisible = el.classList.contains('datetime-ready');
734
726
  const { isGridStyle, showMonthAndYear } = this;
735
- let areAllSelectedDatesInSameMonth = true;
736
- if (Array.isArray(valueToProcess)) {
737
- const firstMonth = valueToProcess[0].month;
738
- for (const date of valueToProcess) {
739
- if (date.month !== firstMonth) {
740
- areAllSelectedDatesInSameMonth = false;
741
- break;
742
- }
743
- }
727
+ if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
728
+ /**
729
+ * Only animate if:
730
+ * 1. We're using grid style (wheel style pickers should just jump to new value)
731
+ * 2. The month and/or year actually changed, and both are defined (otherwise there's nothing to animate to)
732
+ * 3. The calendar body is visible (prevents animation when in collapsed datetime-button, for example)
733
+ * 4. The month/year picker is not open (since you wouldn't see the animation anyway)
734
+ */
735
+ this.animateToDate(targetValue);
744
736
  }
745
- /**
746
- * If there is more than one date selected
747
- * and the dates aren't all in the same month,
748
- * then we should neither animate to the date
749
- * nor update the working parts because we do
750
- * not know which date the user wants to view.
751
- */
752
- if (areAllSelectedDatesInSameMonth) {
753
- if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
754
- this.animateToDate(targetValue);
755
- }
756
- else {
757
- /**
758
- * We only need to do this if we didn't just animate to a new month,
759
- * since that calls prevMonth/nextMonth which calls setWorkingParts for us.
760
- */
761
- this.setWorkingParts({
762
- month,
763
- day,
764
- year,
765
- hour,
766
- minute,
767
- ampm,
768
- });
769
- }
737
+ else {
738
+ this.setWorkingParts({
739
+ month,
740
+ day,
741
+ year,
742
+ hour,
743
+ minute,
744
+ ampm,
745
+ });
770
746
  }
771
747
  };
772
748
  this.animateToDate = async (targetValue) => {
@@ -1761,7 +1737,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1761
1737
  const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
1762
1738
  const hasWheelVariant = hasDatePresentation && preferWheel;
1763
1739
  renderHiddenInput(true, el, name, formatValue(value), disabled);
1764
- return (h(Host, { key: 'c3dfea8f46fcbcef38eb9e8a69b1b46a4e4b82fd', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
1740
+ return (h(Host, { key: '20e64fb4cfe3fbd74b24038c89e00651d78b500c', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
1765
1741
  [mode]: true,
1766
1742
  ['datetime-readonly']: readonly,
1767
1743
  ['datetime-disabled']: disabled,
@@ -1771,7 +1747,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1771
1747
  [`datetime-size-${size}`]: true,
1772
1748
  [`datetime-prefer-wheel`]: hasWheelVariant,
1773
1749
  [`datetime-grid`]: isGridStyle,
1774
- })) }, h("div", { key: '75c91243cf6a51f44b83d7cf7d8c0c96bfd3c83f', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1750
+ })) }, h("div", { key: '488fe7bf6b9052e208d65206a580d5d65b945a62', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1775
1751
  }
1776
1752
  get el() { return this; }
1777
1753
  static get watchers() { return {
@@ -72,14 +72,14 @@ const InputPasswordToggle = /*@__PURE__*/ proxyCustomElement(class InputPassword
72
72
  const isPasswordVisible = type === 'text';
73
73
  return (h(Host, { key: '1a28e078c83e74c72d8bb8189ece93ec2e3fa3d0', class: createColorClasses(color, {
74
74
  [mode]: true,
75
- }) }, h("ion-button", { key: '039d1bab764093bb6fe4a34299b0872abda087fd', mode: mode, color: color, fill: "clear", shape: "round", "aria-checked": isPasswordVisible ? 'true' : 'false', "aria-label": "show password", role: "switch", type: "button", onPointerDown: (ev) => {
75
+ }) }, h("ion-button", { key: '61591d11d97f3065240e51d8887f831339fd36cf', mode: mode, color: color, fill: "clear", shape: "round", "aria-checked": isPasswordVisible ? 'true' : 'false', "aria-label": isPasswordVisible ? 'Hide password' : 'Show password', role: "switch", type: "button", onPointerDown: (ev) => {
76
76
  /**
77
77
  * This prevents mobile browsers from
78
78
  * blurring the input when the password toggle
79
79
  * button is activated.
80
80
  */
81
81
  ev.preventDefault();
82
- }, onClick: this.togglePasswordVisibility }, h("ion-icon", { key: '26477ee97b808c3d79944bf5e33d4e05f1ae0b3f', slot: "icon-only", "aria-hidden": "true", icon: isPasswordVisible ? hidePasswordIcon : showPasswordIcon }))));
82
+ }, onClick: this.togglePasswordVisibility }, h("ion-icon", { key: '9d98e6675d5e2adea5c0f56ab67e98b6f57521dd', slot: "icon-only", "aria-hidden": "true", icon: isPasswordVisible ? hidePasswordIcon : showPasswordIcon }))));
83
83
  }
84
84
  get el() { return this; }
85
85
  static get watchers() { return {
@@ -392,8 +392,8 @@ const Searchbar = /*@__PURE__*/ proxyCustomElement(class Searchbar extends HTMLE
392
392
  const clearIcon = this.clearIcon || (mode === 'ios' ? closeCircle : closeSharp);
393
393
  const searchIcon = this.searchIcon || (mode === 'ios' ? searchOutline : searchSharp);
394
394
  const shouldShowCancelButton = this.shouldShowCancelButton();
395
- const cancelButton = this.showCancelButton !== 'never' && (h("button", { key: '989f3e84c472ada6e66dd9b249d0d268bf17ce26', "aria-label": cancelButtonText, "aria-hidden": shouldShowCancelButton ? undefined : 'true', type: "button", tabIndex: mode === 'ios' && !shouldShowCancelButton ? -1 : undefined, onMouseDown: this.onCancelSearchbar, onTouchStart: this.onCancelSearchbar, class: "searchbar-cancel-button" }, h("div", { key: '7d335d4fde33822dc79d26b748ba2e98db7494bb', "aria-hidden": "true" }, mode === 'md' ? (h("ion-icon", { "aria-hidden": "true", mode: mode, icon: this.cancelButtonIcon, lazy: false })) : (cancelButtonText))));
396
- return (h(Host, { key: 'd1a1972725e949fb102c91487aaa7b9d10c2d718', role: "search", "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses(this.color, {
395
+ const cancelButton = this.showCancelButton !== 'never' && (h("button", { key: '4a4bddfaf44acb9ea71d37d11c3fc11450134a5c', "aria-label": cancelButtonText, "aria-hidden": shouldShowCancelButton ? undefined : 'true', type: "button", tabIndex: mode === 'ios' && !shouldShowCancelButton ? -1 : undefined, onMouseDown: this.onCancelSearchbar, onTouchStart: this.onCancelSearchbar, class: "searchbar-cancel-button" }, h("div", { key: '24424547e34a80422f617f5597965724a3ef65f0', "aria-hidden": "true" }, mode === 'md' ? (h("ion-icon", { "aria-hidden": "true", mode: mode, icon: this.cancelButtonIcon, lazy: false })) : (cancelButtonText))));
396
+ return (h(Host, { key: '0c0e7334cb2af87081a278e5a3f6be3dc646a073', role: "search", "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses(this.color, {
397
397
  [mode]: true,
398
398
  'searchbar-animated': animated,
399
399
  'searchbar-disabled': this.disabled,
@@ -403,14 +403,14 @@ const Searchbar = /*@__PURE__*/ proxyCustomElement(class Searchbar extends HTMLE
403
403
  'searchbar-has-focus': this.focused,
404
404
  'searchbar-should-show-clear': this.shouldShowClearButton(),
405
405
  'searchbar-should-show-cancel': this.shouldShowCancelButton(),
406
- }) }, h("div", { key: 'add53640b2994cb6b2bf02792dafe51aba6b1684', class: "searchbar-input-container" }, h("input", Object.assign({ key: '160cc36459a4a652e7f41ccd14dcdc782278779e', "aria-label": "search text", disabled: this.disabled, ref: (el) => (this.nativeInput = el), class: "searchbar-input", inputMode: this.inputmode, enterKeyHint: this.enterkeyhint, name: this.name, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, minLength: this.minlength, maxLength: this.maxlength, placeholder: this.placeholder, type: this.type, value: this.getValue(), autoCapitalize: autocapitalize === 'default' ? undefined : autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, spellcheck: this.spellcheck }, this.inheritedAttributes)), mode === 'md' && cancelButton, h("ion-icon", { key: '8825fd13af0d2dea451ccc0e00ae7b5021dc01c4', "aria-hidden": "true", mode: mode, icon: searchIcon, lazy: false, class: "searchbar-search-icon" }), h("button", { key: '8a7b56da278b9ca5c4f5a4ee9c01924fd5ae29d8', "aria-label": "reset", type: "button", "no-blur": true, class: "searchbar-clear-button", onPointerDown: (ev) => {
406
+ }) }, h("div", { key: '859da78b062b9059701eba166be3bc5417f7395b', class: "searchbar-input-container" }, h("input", Object.assign({ key: '840fd06a1e4b5a8d7f6d7439d02aef9fcb9720b6', "aria-label": "search text", disabled: this.disabled, ref: (el) => (this.nativeInput = el), class: "searchbar-input", inputMode: this.inputmode, enterKeyHint: this.enterkeyhint, name: this.name, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, minLength: this.minlength, maxLength: this.maxlength, placeholder: this.placeholder, type: this.type, value: this.getValue(), autoCapitalize: autocapitalize === 'default' ? undefined : autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, spellcheck: this.spellcheck }, this.inheritedAttributes)), mode === 'md' && cancelButton, h("ion-icon", { key: 'a5aaa6a2204d38433cac283dd47b6197499fa585', "aria-hidden": "true", mode: mode, icon: searchIcon, lazy: false, class: "searchbar-search-icon" }), h("button", { key: 'cf62c8969c5c916ac838e122a0ad45b2ae234791', "aria-label": "reset", type: "button", "no-blur": true, class: "searchbar-clear-button", onPointerDown: (ev) => {
407
407
  /**
408
408
  * This prevents mobile browsers from
409
409
  * blurring the input when the clear
410
410
  * button is activated.
411
411
  */
412
412
  ev.preventDefault();
413
- }, onClick: () => this.onClearInput(true) }, h("ion-icon", { key: '24c55274516ab012d8c25f03525c6cdb9409e52f', "aria-hidden": "true", mode: mode, icon: clearIcon, lazy: false, class: "searchbar-clear-icon" }))), mode === 'ios' && cancelButton));
413
+ }, onClick: () => this.onClearInput(true) }, h("ion-icon", { key: 'b1a75f0964fc2119479e246dc27bef7cc33bd19f', "aria-hidden": "true", mode: mode, icon: clearIcon, lazy: false, class: "searchbar-clear-icon" }))), mode === 'ios' && cancelButton));
414
414
  }
415
415
  get el() { return this; }
416
416
  static get watchers() { return {
@@ -582,7 +582,47 @@ const iosEnterAnimation = (baseEl, opts) => {
582
582
  .addElement(baseEl)
583
583
  .easing('cubic-bezier(0.32,0.72,0,1)')
584
584
  .duration(500)
585
- .addAnimation([wrapperAnimation]);
585
+ .addAnimation([wrapperAnimation])
586
+ .beforeAddWrite(() => {
587
+ if (expandToScroll) {
588
+ // Scroll can only be done when the modal is fully expanded.
589
+ return;
590
+ }
591
+ /**
592
+ * There are some browsers that causes flickering when
593
+ * dragging the content when scroll is enabled at every
594
+ * breakpoint. This is due to the wrapper element being
595
+ * transformed off the screen and having a snap animation.
596
+ *
597
+ * A workaround is to clone the footer element and append
598
+ * it outside of the wrapper element. This way, the footer
599
+ * is still visible and the drag can be done without
600
+ * flickering. The original footer is hidden until the modal
601
+ * is dismissed. This maintains the animation of the footer
602
+ * when the modal is dismissed.
603
+ *
604
+ * The workaround needs to be done before the animation starts
605
+ * so there are no flickering issues.
606
+ */
607
+ const ionFooter = baseEl.querySelector('ion-footer');
608
+ /**
609
+ * This check is needed to prevent more than one footer
610
+ * from being appended to the shadow root.
611
+ * Otherwise, iOS and MD enter animations would append
612
+ * the footer twice.
613
+ */
614
+ const ionFooterAlreadyAppended = baseEl.shadowRoot.querySelector('ion-footer');
615
+ if (ionFooter && !ionFooterAlreadyAppended) {
616
+ const footerHeight = ionFooter.clientHeight;
617
+ const clonedFooter = ionFooter.cloneNode(true);
618
+ baseEl.shadowRoot.appendChild(clonedFooter);
619
+ ionFooter.style.setProperty('display', 'none');
620
+ ionFooter.setAttribute('aria-hidden', 'true');
621
+ // Padding is added to prevent some content from being hidden.
622
+ const page = baseEl.querySelector('.ion-page');
623
+ page.style.setProperty('padding-bottom', `${footerHeight}px`);
624
+ }
625
+ });
586
626
  if (contentAnimation) {
587
627
  baseAnimation.addAnimation(contentAnimation);
588
628
  }
@@ -663,7 +703,7 @@ const createLeaveAnimation$1 = () => {
663
703
  * iOS Modal Leave Animation
664
704
  */
665
705
  const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
666
- const { presentingEl, currentBreakpoint } = opts;
706
+ const { presentingEl, currentBreakpoint, expandToScroll } = opts;
667
707
  const root = getElementRoot(baseEl);
668
708
  const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation$1();
669
709
  backdropAnimation.addElement(root.querySelector('ion-backdrop'));
@@ -672,7 +712,29 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
672
712
  .addElement(baseEl)
673
713
  .easing('cubic-bezier(0.32,0.72,0,1)')
674
714
  .duration(duration)
675
- .addAnimation(wrapperAnimation);
715
+ .addAnimation(wrapperAnimation)
716
+ .beforeAddWrite(() => {
717
+ if (expandToScroll) {
718
+ // Scroll can only be done when the modal is fully expanded.
719
+ return;
720
+ }
721
+ /**
722
+ * If expandToScroll is disabled, we need to swap
723
+ * the visibility to the original, so the footer
724
+ * dismisses with the modal and doesn't stay
725
+ * until the modal is removed from the DOM.
726
+ */
727
+ const ionFooter = baseEl.querySelector('ion-footer');
728
+ if (ionFooter) {
729
+ const clonedFooter = baseEl.shadowRoot.querySelector('ion-footer');
730
+ ionFooter.style.removeProperty('display');
731
+ ionFooter.removeAttribute('aria-hidden');
732
+ clonedFooter.style.setProperty('display', 'none');
733
+ clonedFooter.setAttribute('aria-hidden', 'true');
734
+ const page = baseEl.querySelector('.ion-page');
735
+ page.style.removeProperty('padding-bottom');
736
+ }
737
+ });
676
738
  if (presentingEl) {
677
739
  const isMobile = window.innerWidth < 768;
678
740
  const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
@@ -768,7 +830,47 @@ const mdEnterAnimation = (baseEl, opts) => {
768
830
  .addElement(baseEl)
769
831
  .easing('cubic-bezier(0.36,0.66,0.04,1)')
770
832
  .duration(280)
771
- .addAnimation([backdropAnimation, wrapperAnimation]);
833
+ .addAnimation([backdropAnimation, wrapperAnimation])
834
+ .beforeAddWrite(() => {
835
+ if (expandToScroll) {
836
+ // Scroll can only be done when the modal is fully expanded.
837
+ return;
838
+ }
839
+ /**
840
+ * There are some browsers that causes flickering when
841
+ * dragging the content when scroll is enabled at every
842
+ * breakpoint. This is due to the wrapper element being
843
+ * transformed off the screen and having a snap animation.
844
+ *
845
+ * A workaround is to clone the footer element and append
846
+ * it outside of the wrapper element. This way, the footer
847
+ * is still visible and the drag can be done without
848
+ * flickering. The original footer is hidden until the modal
849
+ * is dismissed. This maintains the animation of the footer
850
+ * when the modal is dismissed.
851
+ *
852
+ * The workaround needs to be done before the animation starts
853
+ * so there are no flickering issues.
854
+ */
855
+ const ionFooter = baseEl.querySelector('ion-footer');
856
+ /**
857
+ * This check is needed to prevent more than one footer
858
+ * from being appended to the shadow root.
859
+ * Otherwise, iOS and MD enter animations would append
860
+ * the footer twice.
861
+ */
862
+ const ionFooterAlreadyAppended = baseEl.shadowRoot.querySelector('ion-footer');
863
+ if (ionFooter && !ionFooterAlreadyAppended) {
864
+ const footerHeight = ionFooter.clientHeight;
865
+ const clonedFooter = ionFooter.cloneNode(true);
866
+ baseEl.shadowRoot.appendChild(clonedFooter);
867
+ ionFooter.style.setProperty('display', 'none');
868
+ ionFooter.setAttribute('aria-hidden', 'true');
869
+ // Padding is added to prevent some content from being hidden.
870
+ const page = baseEl.querySelector('.ion-page');
871
+ page.style.setProperty('padding-bottom', `${footerHeight}px`);
872
+ }
873
+ });
772
874
  if (contentAnimation) {
773
875
  baseAnimation.addAnimation(contentAnimation);
774
876
  }
@@ -787,7 +889,7 @@ const createLeaveAnimation = () => {
787
889
  * Md Modal Leave Animation
788
890
  */
789
891
  const mdLeaveAnimation = (baseEl, opts) => {
790
- const { currentBreakpoint } = opts;
892
+ const { currentBreakpoint, expandToScroll } = opts;
791
893
  const root = getElementRoot(baseEl);
792
894
  const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation();
793
895
  backdropAnimation.addElement(root.querySelector('ion-backdrop'));
@@ -795,7 +897,29 @@ const mdLeaveAnimation = (baseEl, opts) => {
795
897
  const baseAnimation = createAnimation()
796
898
  .easing('cubic-bezier(0.47,0,0.745,0.715)')
797
899
  .duration(200)
798
- .addAnimation([backdropAnimation, wrapperAnimation]);
900
+ .addAnimation([backdropAnimation, wrapperAnimation])
901
+ .beforeAddWrite(() => {
902
+ if (expandToScroll) {
903
+ // Scroll can only be done when the modal is fully expanded.
904
+ return;
905
+ }
906
+ /**
907
+ * If expandToScroll is disabled, we need to swap
908
+ * the visibility to the original, so the footer
909
+ * dismisses with the modal and doesn't stay
910
+ * until the modal is removed from the DOM.
911
+ */
912
+ const ionFooter = baseEl.querySelector('ion-footer');
913
+ if (ionFooter) {
914
+ const clonedFooter = baseEl.shadowRoot.querySelector('ion-footer');
915
+ ionFooter.style.removeProperty('display');
916
+ ionFooter.removeAttribute('aria-hidden');
917
+ clonedFooter.style.setProperty('display', 'none');
918
+ clonedFooter.setAttribute('aria-hidden', 'true');
919
+ const page = baseEl.querySelector('.ion-page');
920
+ page.style.removeProperty('padding-bottom');
921
+ }
922
+ });
799
923
  return baseAnimation;
800
924
  };
801
925
 
@@ -827,8 +951,6 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
827
951
  let offset = 0;
828
952
  let canDismissBlocksGesture = false;
829
953
  let cachedScrollEl = null;
830
- let cachedFooterYPosition = null;
831
- let currentFooterState = null;
832
954
  const canDismissMaxStep = 0.95;
833
955
  const maxBreakpoint = breakpoints[breakpoints.length - 1];
834
956
  const minBreakpoint = breakpoints[0];
@@ -858,38 +980,29 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
858
980
  baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
859
981
  };
860
982
  /**
861
- * Toggles the footer to an absolute position while moving to prevent
862
- * it from shaking while the sheet is being dragged.
863
- * @param footer Whether the footer is in a moving or stationary position.
983
+ * Toggles the visible modal footer when `expandToScroll` is disabled.
984
+ * @param footer The footer to show.
864
985
  */
865
- const swapFooterPosition = (newPosition) => {
866
- var _a, _b;
986
+ const swapFooterVisibility = (footer) => {
867
987
  const originalFooter = baseEl.querySelector('ion-footer');
868
988
  if (!originalFooter) {
869
989
  return;
870
990
  }
871
- currentFooterState = newPosition;
872
- if (newPosition === 'stationary') {
873
- // Reset positioning styles to allow normal document flow
874
- originalFooter.style.removeProperty('position');
875
- originalFooter.style.removeProperty('bottom');
876
- (_a = originalFooter.parentElement) === null || _a === void 0 ? void 0 : _a.style.removeProperty('padding-bottom');
991
+ const clonedFooter = wrapperEl.nextElementSibling;
992
+ const footerToHide = footer === 'original' ? clonedFooter : originalFooter;
993
+ const footerToShow = footer === 'original' ? originalFooter : clonedFooter;
994
+ footerToShow.style.removeProperty('display');
995
+ footerToShow.removeAttribute('aria-hidden');
996
+ const page = baseEl.querySelector('.ion-page');
997
+ if (footer === 'original') {
998
+ page.style.removeProperty('padding-bottom');
877
999
  }
878
1000
  else {
879
- // Add padding to the parent element to prevent content from being hidden
880
- // when the footer is positioned absolutely. This has to be done before we
881
- // make the footer absolutely positioned or we may accidentally cause the
882
- // sheet to scroll.
883
- const footerHeight = originalFooter.clientHeight;
884
- (_b = originalFooter.parentElement) === null || _b === void 0 ? void 0 : _b.style.setProperty('padding-bottom', `${footerHeight}px`);
885
- // Apply positioning styles to keep footer at bottom
886
- originalFooter.style.setProperty('position', 'absolute');
887
- originalFooter.style.setProperty('bottom', '0');
888
- // Also cache the footer Y position, which we use to determine if the
889
- // sheet has been moved below the footer. When that happens, we need to swap
890
- // the position back so it will collapse correctly.
891
- cachedFooterYPosition = originalFooter.getBoundingClientRect().top + window.scrollY;
1001
+ const pagePadding = footerToShow.clientHeight;
1002
+ page.style.setProperty('padding-bottom', `${pagePadding}px`);
892
1003
  }
1004
+ footerToHide.style.setProperty('display', 'none');
1005
+ footerToHide.setAttribute('aria-hidden', 'true');
893
1006
  };
894
1007
  /**
895
1008
  * After the entering animation completes,
@@ -983,11 +1096,12 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
983
1096
  }
984
1097
  /**
985
1098
  * If expandToScroll is disabled, we need to swap
986
- * the footer position to moving so that it doesn't shake
987
- * while the sheet is being dragged.
1099
+ * the footer visibility to the original, so if the modal
1100
+ * is dismissed, the footer dismisses with the modal
1101
+ * and doesn't stay on the screen after the modal is gone.
988
1102
  */
989
1103
  if (!expandToScroll) {
990
- swapFooterPosition('moving');
1104
+ swapFooterVisibility('original');
991
1105
  }
992
1106
  /**
993
1107
  * If we are pulling down, then it is possible we are pulling on the content.
@@ -1006,21 +1120,6 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1006
1120
  animation.progressStart(true, 1 - currentBreakpoint);
1007
1121
  };
1008
1122
  const onMove = (detail) => {
1009
- /**
1010
- * If `expandToScroll` is disabled, we need to see if we're currently below
1011
- * the footer element and the footer is in a stationary position. If so,
1012
- * we need to make the stationary the original position so that the footer
1013
- * collapses with the sheet.
1014
- */
1015
- if (!expandToScroll && cachedFooterYPosition !== null && currentFooterState !== null) {
1016
- // Check if we need to swap the footer position
1017
- if (detail.currentY >= cachedFooterYPosition && currentFooterState === 'moving') {
1018
- swapFooterPosition('stationary');
1019
- }
1020
- else if (detail.currentY < cachedFooterYPosition && currentFooterState === 'stationary') {
1021
- swapFooterPosition('moving');
1022
- }
1023
- }
1024
1123
  /**
1025
1124
  * If `expandToScroll` is disabled, and an upwards swipe gesture is done within
1026
1125
  * the scrollable content, we should not allow the swipe gesture to continue.
@@ -1154,6 +1253,14 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1154
1253
  * snapping animation completes.
1155
1254
  */
1156
1255
  gesture.enable(false);
1256
+ /**
1257
+ * If expandToScroll is disabled, we need to swap
1258
+ * the footer visibility to the cloned one so the footer
1259
+ * doesn't flicker when the sheet's height is animated.
1260
+ */
1261
+ if (!expandToScroll && shouldRemainOpen) {
1262
+ swapFooterVisibility('cloned');
1263
+ }
1157
1264
  if (shouldPreventDismiss) {
1158
1265
  handleCanDismiss(baseEl, animation);
1159
1266
  }
@@ -1174,14 +1281,6 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1174
1281
  animation
1175
1282
  .onFinish(() => {
1176
1283
  if (shouldRemainOpen) {
1177
- /**
1178
- * If expandToScroll is disabled, we need to swap
1179
- * the footer position to stationary so that it
1180
- * will act as it would by default
1181
- */
1182
- if (!expandToScroll) {
1183
- swapFooterPosition('stationary');
1184
- }
1185
1284
  /**
1186
1285
  * Once the snapping animation completes,
1187
1286
  * we need to reset the animation to go
@@ -335,7 +335,7 @@ const PickerColumnCmp = /*@__PURE__*/ proxyCustomElement(class PickerColumnCmp e
335
335
  const colEl = this.optsEl;
336
336
  if (colEl) {
337
337
  // DOM READ
338
- // We perfom a DOM read over a rendered item, this needs to happen after the first render or after the the column has changed
338
+ // We perfom a DOM read over a rendered item, this needs to happen after the first render or after the column has changed
339
339
  this.optHeight = colEl.firstElementChild ? colEl.firstElementChild.clientHeight : 0;
340
340
  }
341
341
  this.refresh(forceRefresh, animated);
@@ -343,9 +343,9 @@ const PickerColumnCmp = /*@__PURE__*/ proxyCustomElement(class PickerColumnCmp e
343
343
  render() {
344
344
  const col = this.col;
345
345
  const mode = getIonMode(this);
346
- return (h(Host, { key: '88a3c9397c9ac92dd814074c8ae6ecf8e3420a2c', class: Object.assign({ [mode]: true, 'picker-col': true, 'picker-opts-left': this.col.align === 'left', 'picker-opts-right': this.col.align === 'right' }, getClassMap(col.cssClass)), style: {
346
+ return (h(Host, { key: '10ef653cbae8e1ed92a23fa17f3396082e35951f', class: Object.assign({ [mode]: true, 'picker-col': true, 'picker-opts-left': this.col.align === 'left', 'picker-opts-right': this.col.align === 'right' }, getClassMap(col.cssClass)), style: {
347
347
  'max-width': this.col.columnWidth,
348
- } }, col.prefix && (h("div", { key: '4491a705d15337e6f45f3cf6fd21af5242474729', class: "picker-prefix", style: { width: col.prefixWidth } }, col.prefix)), h("div", { key: 'b0dd4b7a7a4c1edc4b73e7fb134ac85264072365', class: "picker-opts", style: { maxWidth: col.optionsWidth }, ref: (el) => (this.optsEl = el) }, col.options.map((o, index) => (h("button", { "aria-label": o.ariaLabel, class: { 'picker-opt': true, 'picker-opt-disabled': !!o.disabled }, "opt-index": index }, o.text)))), col.suffix && (h("div", { key: 'c16419ce6481d60fc3ba6b8d102a4edf0ede02aa', class: "picker-suffix", style: { width: col.suffixWidth } }, col.suffix))));
348
+ } }, col.prefix && (h("div", { key: '253066708012034206b1d3d466ea48d0a3be3323', class: "picker-prefix", style: { width: col.prefixWidth } }, col.prefix)), h("div", { key: '15fa07307d4d2b4994504a5bf2de8db05b51cd2c', class: "picker-opts", style: { maxWidth: col.optionsWidth }, ref: (el) => (this.optsEl = el) }, col.options.map((o, index) => (h("button", { "aria-label": o.ariaLabel, class: { 'picker-opt': true, 'picker-opt-disabled': !!o.disabled }, "opt-index": index }, o.text)))), col.suffix && (h("div", { key: '4db779830b1e6aa6b324e5a72541d4f610ac1ff5', class: "picker-suffix", style: { width: col.suffixWidth } }, col.suffix))));
349
349
  }
350
350
  get el() { return this; }
351
351
  static get watchers() { return {
@@ -210,6 +210,20 @@ const Button = class {
210
210
  this.formButtonEl.disabled = disabled;
211
211
  }
212
212
  }
213
+ /**
214
+ * This component is used within the `ion-input-password-toggle` component
215
+ * to toggle the visibility of the password input.
216
+ * These attributes need to update based on the state of the password input.
217
+ * Otherwise, the values will be stale.
218
+ *
219
+ * @param newValue
220
+ * @param _oldValue
221
+ * @param propName
222
+ */
223
+ onAriaChanged(newValue, _oldValue, propName) {
224
+ this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { [propName]: newValue });
225
+ index.forceUpdate(this);
226
+ }
213
227
  /**
214
228
  * This is responsible for rendering a hidden native
215
229
  * button element inside the associated form. This allows
@@ -347,7 +361,7 @@ const Button = class {
347
361
  {
348
362
  type !== 'button' && this.renderHiddenButton();
349
363
  }
350
- return (index.h(index.Host, { key: 'e213b0bb76b3f90f883b1a0ea463bb86c2df69c3', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: theme.createColorClasses(color, {
364
+ return (index.h(index.Host, { key: 'b105ad09215adb3ca2298acdadf0dc9154bbb9b0', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: theme.createColorClasses(color, {
351
365
  [mode]: true,
352
366
  [buttonType]: true,
353
367
  [`${buttonType}-${expand}`]: expand !== undefined,
@@ -362,11 +376,13 @@ const Button = class {
362
376
  'button-disabled': disabled,
363
377
  'ion-activatable': true,
364
378
  'ion-focusable': true,
365
- }) }, index.h(TagType, Object.assign({ key: 'b7c2a46fb994024841219316f4089335fa463d84' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), index.h("span", { key: '3e07a5c9f86836f9fbaefc6c617bdde6eb6f70cd', class: "button-inner" }, index.h("slot", { key: '41c08ae09aed16faaa57707d229ff75d97f0731c', name: "icon-only", onSlotchange: this.slotChanged }), index.h("slot", { key: 'ab8b749e4572884cc04970a7594466b4a24c886e', name: "start" }), index.h("slot", { key: '397f7ff48ea45e82029414be95d29ae86e12c3a9' }), index.h("slot", { key: '9a5627713002e8be3738d392b616f6e951b70e12', name: "end" })), mode === 'md' && index.h("ion-ripple-effect", { key: '105566543ceda102474edab7ca8a44c7e71af589', type: this.rippleType }))));
379
+ }) }, index.h(TagType, Object.assign({ key: '66b4e7112bcb9e41d5a723fbbadb0a3104f9ee1d' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), index.h("span", { key: '1439fc3da280221028dcf7ce8ec9dab273c4d4bb', class: "button-inner" }, index.h("slot", { key: 'd5269ae1afc87ec7b99746032f59cbae93720a9f', name: "icon-only", onSlotchange: this.slotChanged }), index.h("slot", { key: '461c83e97aa246aa86d83e14f1e15a288d35041e', name: "start" }), index.h("slot", { key: '807170d47101f9f6a333dd4ff489c89284f306fe' }), index.h("slot", { key: 'e67f116dd0349a0d27893e4f3ff0ccef1d402f80', name: "end" })), mode === 'md' && index.h("ion-ripple-effect", { key: '273f0bd9645a36c1bfd18a5c2ab4f81e22b7b989', type: this.rippleType }))));
366
380
  }
367
381
  get el() { return index.getElement(this); }
368
382
  static get watchers() { return {
369
- "disabled": ["disabledChanged"]
383
+ "disabled": ["disabledChanged"],
384
+ "aria-checked": ["onAriaChanged"],
385
+ "aria-label": ["onAriaChanged"]
370
386
  }; }
371
387
  };
372
388
  Button.style = {