@ionic/core 7.4.2-dev.11695927273.1323de22 → 7.4.2-dev.11696878562.16da82aa

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 (48) hide show
  1. package/components/alert.js +8 -0
  2. package/components/index.js +1 -0
  3. package/components/ion-select.js +1 -1
  4. package/components/ion-toast.js +144 -113
  5. package/dist/cjs/index.cjs.js +2 -0
  6. package/dist/cjs/ion-alert.cjs.entry.js +8 -0
  7. package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
  8. package/dist/cjs/ion-toast.cjs.entry.js +163 -132
  9. package/dist/collection/components/alert/alert.js +8 -0
  10. package/dist/collection/components/alert/test/a11y/alert.e2e.js +11 -0
  11. package/dist/collection/components/select/select.js +1 -1
  12. package/dist/collection/components/toast/animations/ios.enter.js +1 -39
  13. package/dist/collection/components/toast/animations/ios.leave.js +4 -9
  14. package/dist/collection/components/toast/animations/md.enter.js +1 -40
  15. package/dist/collection/components/toast/animations/utils.js +85 -0
  16. package/dist/collection/components/toast/toast.js +58 -31
  17. package/dist/collection/index.js +1 -0
  18. package/dist/docs.json +3 -7
  19. package/dist/esm/index.js +1 -0
  20. package/dist/esm/ion-alert.entry.js +8 -0
  21. package/dist/esm/ion-select_3.entry.js +1 -1
  22. package/dist/esm/ion-toast.entry.js +144 -113
  23. package/dist/esm-es5/index.js +1 -1
  24. package/dist/esm-es5/ion-alert.entry.js +1 -1
  25. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  26. package/dist/esm-es5/ion-toast.entry.js +1 -1
  27. package/dist/ionic/index.esm.js +1 -1
  28. package/dist/ionic/ionic.esm.js +1 -1
  29. package/dist/ionic/p-06c94b76.entry.js +4 -0
  30. package/dist/ionic/{p-2df840d9.system.entry.js → p-1e207aa7.system.entry.js} +1 -1
  31. package/dist/ionic/p-2bea5600.entry.js +4 -0
  32. package/dist/ionic/p-4e312f80.system.entry.js +4 -0
  33. package/dist/ionic/p-5f6605c4.entry.js +4 -0
  34. package/dist/ionic/{p-5d522814.system.entry.js → p-6cb04881.system.entry.js} +1 -1
  35. package/dist/ionic/p-6edbc09b.system.js +1 -1
  36. package/dist/ionic/p-8a1faf2c.system.js +4 -0
  37. package/dist/types/components/toast/animations/ios.leave.d.ts +2 -2
  38. package/dist/types/components/toast/animations/utils.d.ts +18 -0
  39. package/dist/types/components/toast/toast-interface.d.ts +8 -3
  40. package/dist/types/components/toast/toast.d.ts +12 -0
  41. package/dist/types/index.d.ts +1 -0
  42. package/hydrate/index.js +153 -114
  43. package/package.json +1 -1
  44. package/dist/ionic/p-1f448082.system.entry.js +0 -4
  45. package/dist/ionic/p-35d1c3bb.system.js +0 -4
  46. package/dist/ionic/p-8a26eaba.entry.js +0 -4
  47. package/dist/ionic/p-990aaa2f.entry.js +0 -4
  48. package/dist/ionic/p-c44645f2.entry.js +0 -4
@@ -166,6 +166,14 @@ const Alert = /*@__PURE__*/ proxyCustomElement(class Alert extends HTMLElement {
166
166
  }
167
167
  onKeydown(ev) {
168
168
  const inputTypes = new Set(this.processedInputs.map((i) => i.type));
169
+ /**
170
+ * Based on keyboard navigation requirements, the
171
+ * checkbox should not respond to the enter keydown event.
172
+ */
173
+ if (inputTypes.has('checkbox') && ev.key === 'Enter') {
174
+ ev.preventDefault();
175
+ return;
176
+ }
169
177
  // The only inputs we want to navigate between using arrow keys are the radios
170
178
  // ignore the keydown event if it is not on a radio button
171
179
  if (!inputTypes.has('radio') ||
@@ -11,6 +11,7 @@ export { createGesture } from './index3.js';
11
11
  export { g as getPlatforms, i as initialize, a as isPlatform } from './ionic-global.js';
12
12
  export { c as componentOnReady } from './helpers.js';
13
13
  export { I as IonicSafeString, g as getMode, s as setupConfig } from './config.js';
14
+ export { o as openURL } from './theme.js';
14
15
  export { m as menuController } from './index4.js';
15
16
  export { b as actionSheetController, a as alertController, l as loadingController, m as modalController, p as pickerController, c as popoverController, t as toastController } from './overlays.js';
16
17
 
@@ -626,7 +626,7 @@ Developers can use the "legacy" property to continue using the legacy form marku
626
626
  }
627
627
  renderListbox() {
628
628
  const { disabled, inputId, isExpanded } = this;
629
- return (h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "listbox", "aria-expanded": `${isExpanded}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
629
+ return (h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
630
630
  }
631
631
  render() {
632
632
  const { legacyFormController } = this;
@@ -20,46 +20,9 @@ import { d as defineCustomElement$2 } from './ripple-effect.js';
20
20
  const iosEnterAnimation = (baseEl, opts) => {
21
21
  const baseAnimation = createAnimation();
22
22
  const wrapperAnimation = createAnimation();
23
- const { position, positionAnchor } = opts;
23
+ const { position, top, bottom } = opts;
24
24
  const root = getElementRoot(baseEl);
25
25
  const wrapperEl = root.querySelector('.toast-wrapper');
26
- /**
27
- * Start with a predefined offset from the edge the toast will be
28
- * positioned relative to. By default, this will be the top edge
29
- * of the screen.
30
- */
31
- let offset = position === 'top' ? 10 : -10;
32
- let top, bottom;
33
- /**
34
- * If positionAnchor is defined, add in the distance from the top
35
- * of the screen to the target anchor edge. For position="top", the
36
- * bottom anchor edge is targeted. For position="bottom", the top
37
- * anchor edge is targeted.
38
- */
39
- if (positionAnchor && win) {
40
- const box = positionAnchor.getBoundingClientRect();
41
- if (position === 'top') {
42
- offset += box.bottom;
43
- }
44
- else if (position === 'bottom') {
45
- /**
46
- * Just box.top is the distance from the top edge of the screen
47
- * to the top edge of the anchor. We want to calculate from the
48
- * bottom edge of the screen instead.
49
- */
50
- offset -= win.innerHeight - box.top;
51
- }
52
- /**
53
- * We don't include safe area here because that should already be
54
- * accounted for when checking the position of the anchor.
55
- */
56
- top = `${offset}px`;
57
- bottom = `${offset}px`;
58
- }
59
- else {
60
- top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
61
- bottom = `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`;
62
- }
63
26
  wrapperAnimation.addElement(wrapperEl);
64
27
  switch (position) {
65
28
  case 'top':
@@ -80,27 +43,22 @@ const iosEnterAnimation = (baseEl, opts) => {
80
43
  /**
81
44
  * iOS Toast Leave Animation
82
45
  */
83
- const iosLeaveAnimation = (baseEl, position) => {
46
+ const iosLeaveAnimation = (baseEl, opts) => {
84
47
  const baseAnimation = createAnimation();
85
48
  const wrapperAnimation = createAnimation();
49
+ const { position, top, bottom } = opts;
86
50
  const root = getElementRoot(baseEl);
87
51
  const wrapperEl = root.querySelector('.toast-wrapper');
88
52
  wrapperAnimation.addElement(wrapperEl);
89
- /**
90
- * For top/bottom positions, we use to() instead of fromTo() so that if
91
- * the positionAnchor prop was used, we don't need to recalculate the
92
- * toast and/or anchor's position and duplicate work from the enter
93
- * animation.
94
- */
95
53
  switch (position) {
96
54
  case 'top':
97
- wrapperAnimation.to('transform', 'translateY(-100%)');
55
+ wrapperAnimation.fromTo('transform', `translateY(${top})`, 'translateY(-100%)');
98
56
  break;
99
57
  case 'middle':
100
58
  wrapperAnimation.fromTo('opacity', 0.99, 0);
101
59
  break;
102
60
  default:
103
- wrapperAnimation.to('transform', 'translateY(100%)');
61
+ wrapperAnimation.fromTo('transform', `translateY(${bottom})`, 'translateY(100%)');
104
62
  break;
105
63
  }
106
64
  return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
@@ -112,47 +70,9 @@ const iosLeaveAnimation = (baseEl, position) => {
112
70
  const mdEnterAnimation = (baseEl, opts) => {
113
71
  const baseAnimation = createAnimation();
114
72
  const wrapperAnimation = createAnimation();
115
- const { position, positionAnchor } = opts;
73
+ const { position, top, bottom } = opts;
116
74
  const root = getElementRoot(baseEl);
117
75
  const wrapperEl = root.querySelector('.toast-wrapper');
118
- /**
119
- * Start with a predefined offset from the edge the toast will be
120
- * positioned relative to. By default, this will be the top edge
121
- * of the screen for position="top", or the bottom edge for
122
- * position="bottom".
123
- */
124
- let offset = 8;
125
- let top, bottom;
126
- /**
127
- * If positionAnchor is defined, add in the distance from the target
128
- * screen edge to the target anchor edge. For position="top", the
129
- * bottom anchor edge is targeted. For position="bottom", the top
130
- * anchor edge is targeted.
131
- */
132
- if (positionAnchor && win) {
133
- const box = positionAnchor.getBoundingClientRect();
134
- if (position === 'top') {
135
- offset += box.bottom;
136
- }
137
- else if (position === 'bottom') {
138
- /**
139
- * Just box.top is the distance from the top edge of the screen
140
- * to the top edge of the anchor. We want to calculate from the
141
- * bottom edge of the screen instead.
142
- */
143
- offset += win.innerHeight - box.top;
144
- }
145
- /**
146
- * We don't include safe area here because that should already be
147
- * accounted for when checking the position of the anchor.
148
- */
149
- top = `${offset}px`;
150
- bottom = `${offset}px`;
151
- }
152
- else {
153
- top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
154
- bottom = `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`;
155
- }
156
76
  wrapperAnimation.addElement(wrapperEl);
157
77
  switch (position) {
158
78
  case 'top':
@@ -184,6 +104,87 @@ const mdLeaveAnimation = (baseEl) => {
184
104
  return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
185
105
  };
186
106
 
107
+ /**
108
+ * Calculate the CSS top and bottom position of the toast, to be used
109
+ * as starting points for the animation keyframes.
110
+ *
111
+ * Note that MD animates bottom-positioned toasts using style.bottom,
112
+ * which calculates from the bottom edge of the screen, while iOS uses
113
+ * translateY, which calculates from the top edge of the screen. This
114
+ * is why the bottom calculates differ slightly between modes.
115
+ *
116
+ * @param position The value of the toast's position prop.
117
+ * @param positionAnchor The element the toast should be anchored to,
118
+ * if applicable.
119
+ * @param mode The toast component's mode (md, ios, etc).
120
+ * @param toast A reference to the toast element itself.
121
+ */
122
+ function getAnimationPosition(position, positionAnchor, mode, toast) {
123
+ /**
124
+ * Start with a predefined offset from the edge the toast will be
125
+ * positioned relative to, whether on the screen or anchor element.
126
+ */
127
+ let offset;
128
+ if (mode === 'md') {
129
+ offset = 8;
130
+ }
131
+ else {
132
+ offset = position === 'top' ? 10 : -10;
133
+ }
134
+ /**
135
+ * If positionAnchor is defined, add in the distance from the target
136
+ * screen edge to the target anchor edge. For position="top", the
137
+ * bottom anchor edge is targeted. For position="bottom", the top
138
+ * anchor edge is targeted.
139
+ */
140
+ if (positionAnchor && win) {
141
+ warnIfAnchorIsHidden(positionAnchor, toast);
142
+ const box = positionAnchor.getBoundingClientRect();
143
+ if (position === 'top') {
144
+ offset += box.bottom;
145
+ }
146
+ else if (position === 'bottom') {
147
+ /**
148
+ * Just box.top is the distance from the top edge of the screen
149
+ * to the top edge of the anchor. We want to calculate from the
150
+ * bottom edge of the screen instead.
151
+ */
152
+ if (mode === 'md') {
153
+ offset += win.innerHeight - box.top;
154
+ }
155
+ else {
156
+ offset -= win.innerHeight - box.top;
157
+ }
158
+ }
159
+ /**
160
+ * We don't include safe area here because that should already be
161
+ * accounted for when checking the position of the anchor.
162
+ */
163
+ return {
164
+ top: `${offset}px`,
165
+ bottom: `${offset}px`,
166
+ };
167
+ }
168
+ else {
169
+ return {
170
+ top: `calc(${offset}px + var(--ion-safe-area-top, 0px))`,
171
+ bottom: mode === 'md'
172
+ ? `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`
173
+ : `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`,
174
+ };
175
+ }
176
+ }
177
+ /**
178
+ * If the anchor element is hidden, getBoundingClientRect()
179
+ * will return all 0s for it, which can cause unexpected
180
+ * results in the position calculation when animating.
181
+ */
182
+ function warnIfAnchorIsHidden(positionAnchor, toast) {
183
+ if (positionAnchor.offsetParent === null) {
184
+ printIonWarning('The positionAnchor element for ion-toast was found in the DOM, but appears to be hidden. This may lead to unexpected positioning of the toast.', toast);
185
+ }
186
+ }
187
+
187
188
  const toastIosCss = ":host{--border-width:0;--border-style:none;--border-color:initial;--box-shadow:none;--min-width:auto;--width:auto;--min-height:auto;--height:auto;--max-height:auto;--white-space:normal;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);contain:strict;z-index:1001;pointer-events:none}@supports (inset-inline-start: 0){:host{inset-inline-start:0}}@supports not (inset-inline-start: 0){:host{left:0}:host-context([dir=rtl]){left:unset;right:unset;right:0}@supports selector(:dir(rtl)){:host:dir(rtl){left:unset;right:unset;right:0}}}:host(.overlay-hidden){display:none}:host(.ion-color){--button-color:inherit;color:var(--ion-color-contrast)}:host(.ion-color) .toast-button-cancel{color:inherit}:host(.ion-color) .toast-wrapper{background:var(--ion-color-base)}.toast-wrapper{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}@supports (inset-inline-start: 0){.toast-wrapper{inset-inline-start:var(--start);inset-inline-end:var(--end)}}@supports not (inset-inline-start: 0){.toast-wrapper{left:var(--start);right:var(--end)}:host-context([dir=rtl]) .toast-wrapper{left:unset;right:unset;left:var(--end);right:var(--start)}[dir=rtl] .toast-wrapper{left:unset;right:unset;left:var(--end);right:var(--start)}@supports selector(:dir(rtl)){.toast-wrapper:dir(rtl){left:unset;right:unset;left:var(--end);right:var(--start)}}}.toast-container{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;pointer-events:auto;height:inherit;min-height:inherit;max-height:inherit;contain:content}.toast-layout-stacked .toast-container{-ms-flex-wrap:wrap;flex-wrap:wrap}.toast-layout-baseline .toast-content{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center}.toast-icon{-webkit-margin-start:16px;margin-inline-start:16px}.toast-message{-ms-flex:1;flex:1;white-space:var(--white-space)}.toast-button-group{display:-ms-flexbox;display:flex}.toast-layout-stacked .toast-button-group{-ms-flex-pack:end;justify-content:end;width:100%}.toast-button{border:0;outline:none;color:var(--button-color);z-index:0}.toast-icon,.toast-button-icon{font-size:1.4em}.toast-button-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}@media (any-hover: hover){.toast-button:hover{cursor:pointer}}:host{--background:var(--ion-color-step-50, #f2f2f2);--border-radius:14px;--button-color:var(--ion-color-primary, #3880ff);--color:var(--ion-color-step-850, #262626);--max-width:700px;--start:10px;--end:10px;font-size:14px}.toast-wrapper{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;z-index:10}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.toast-translucent) .toast-wrapper{background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}:host(.ion-color.toast-translucent) .toast-wrapper{background:rgba(var(--ion-color-base-rgb), 0.8)}}.toast-wrapper.toast-top{-webkit-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0);top:0}.toast-wrapper.toast-middle{opacity:0.01}.toast-wrapper.toast-bottom{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);bottom:0}.toast-content{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:15px;padding-bottom:15px}.toast-header{margin-bottom:2px;font-weight:500}.toast-button{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:10px;padding-bottom:10px;height:44px;-webkit-transition:background-color, opacity 100ms linear;transition:background-color, opacity 100ms linear;border:0;background-color:transparent;font-family:var(--ion-font-family);font-size:17px;font-weight:500;overflow:hidden}.toast-button.ion-activated{opacity:0.4}@media (any-hover: hover){.toast-button:hover{opacity:0.6}}";
188
189
 
189
190
  const toastMdCss = ":host{--border-width:0;--border-style:none;--border-color:initial;--box-shadow:none;--min-width:auto;--width:auto;--min-height:auto;--height:auto;--max-height:auto;--white-space:normal;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);contain:strict;z-index:1001;pointer-events:none}@supports (inset-inline-start: 0){:host{inset-inline-start:0}}@supports not (inset-inline-start: 0){:host{left:0}:host-context([dir=rtl]){left:unset;right:unset;right:0}@supports selector(:dir(rtl)){:host:dir(rtl){left:unset;right:unset;right:0}}}:host(.overlay-hidden){display:none}:host(.ion-color){--button-color:inherit;color:var(--ion-color-contrast)}:host(.ion-color) .toast-button-cancel{color:inherit}:host(.ion-color) .toast-wrapper{background:var(--ion-color-base)}.toast-wrapper{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}@supports (inset-inline-start: 0){.toast-wrapper{inset-inline-start:var(--start);inset-inline-end:var(--end)}}@supports not (inset-inline-start: 0){.toast-wrapper{left:var(--start);right:var(--end)}:host-context([dir=rtl]) .toast-wrapper{left:unset;right:unset;left:var(--end);right:var(--start)}[dir=rtl] .toast-wrapper{left:unset;right:unset;left:var(--end);right:var(--start)}@supports selector(:dir(rtl)){.toast-wrapper:dir(rtl){left:unset;right:unset;left:var(--end);right:var(--start)}}}.toast-container{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;pointer-events:auto;height:inherit;min-height:inherit;max-height:inherit;contain:content}.toast-layout-stacked .toast-container{-ms-flex-wrap:wrap;flex-wrap:wrap}.toast-layout-baseline .toast-content{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center}.toast-icon{-webkit-margin-start:16px;margin-inline-start:16px}.toast-message{-ms-flex:1;flex:1;white-space:var(--white-space)}.toast-button-group{display:-ms-flexbox;display:flex}.toast-layout-stacked .toast-button-group{-ms-flex-pack:end;justify-content:end;width:100%}.toast-button{border:0;outline:none;color:var(--button-color);z-index:0}.toast-icon,.toast-button-icon{font-size:1.4em}.toast-button-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}@media (any-hover: hover){.toast-button:hover{cursor:pointer}}:host{--background:var(--ion-color-step-800, #333333);--border-radius:4px;--box-shadow:0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);--button-color:var(--ion-color-primary, #3880ff);--color:var(--ion-color-step-50, #f2f2f2);--max-width:700px;--start:8px;--end:8px;font-size:14px}.toast-wrapper{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;opacity:0.01;z-index:10}.toast-content{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:14px;padding-bottom:14px}.toast-header{margin-bottom:2px;font-weight:500;line-height:20px}.toast-message{line-height:20px}.toast-layout-baseline .toast-button-group-start{-webkit-margin-start:8px;margin-inline-start:8px}.toast-layout-stacked .toast-button-group-start{-webkit-margin-end:8px;margin-inline-end:8px;margin-top:8px}.toast-layout-baseline .toast-button-group-end{-webkit-margin-end:8px;margin-inline-end:8px}.toast-layout-stacked .toast-button-group-end{-webkit-margin-end:8px;margin-inline-end:8px;margin-bottom:8px}.toast-button{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:10px;padding-bottom:10px;position:relative;background-color:transparent;font-family:var(--ion-font-family);font-size:14px;font-weight:500;letter-spacing:0.84px;text-transform:uppercase;overflow:hidden}.toast-button-cancel{color:var(--ion-color-step-100, #e6e6e6)}.toast-button-icon-only{border-radius:50%;-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px;padding-top:9px;padding-bottom:9px;width:36px;height:36px}@media (any-hover: hover){.toast-button:hover{background-color:rgba(var(--ion-color-primary-rgb, 56, 128, 255), 0.08)}.toast-button-cancel:hover{background-color:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.08)}}";
@@ -275,32 +276,18 @@ const Toast = /*@__PURE__*/ proxyCustomElement(class Toast extends HTMLElement {
275
276
  async present() {
276
277
  const unlock = await this.lockController.lock();
277
278
  await this.delegateController.attachViewToDom();
278
- const { position, positionAnchor } = this;
279
- let anchor;
280
- if (position === 'middle' && positionAnchor !== undefined) {
281
- printIonWarning('The positionAnchor property is ignored when using position="middle".', this.el);
282
- }
283
- else if (typeof positionAnchor === 'string') {
284
- /**
285
- * If the anchor is defined as an ID, find the element.
286
- * We do this on every present so the toast doesn't need
287
- * to account for the surrounding DOM changing since the
288
- * last time it was presented.
289
- */
290
- const foundEl = document.getElementById(positionAnchor);
291
- if (foundEl === null) {
292
- printIonWarning(`An anchor element with an ID of ${positionAnchor} was not found in the DOM.`, this.el);
293
- }
294
- else {
295
- anchor = foundEl;
296
- }
297
- }
298
- else {
299
- anchor = positionAnchor;
300
- }
279
+ const { el, position } = this;
280
+ const anchor = this.getAnchorElement();
281
+ const animationPosition = getAnimationPosition(position, anchor, getIonMode(this), el);
282
+ /**
283
+ * Cache the calculated position of the toast, so we can re-use it
284
+ * in the dismiss animation.
285
+ */
286
+ this.lastPresentedPosition = animationPosition;
301
287
  await present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, {
302
288
  position,
303
- positionAnchor: anchor,
289
+ top: animationPosition.top,
290
+ bottom: animationPosition.bottom,
304
291
  });
305
292
  /**
306
293
  * Content is revealed to screen readers after
@@ -323,15 +310,28 @@ const Toast = /*@__PURE__*/ proxyCustomElement(class Toast extends HTMLElement {
323
310
  * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
324
311
  */
325
312
  async dismiss(data, role) {
313
+ var _a, _b;
326
314
  const unlock = await this.lockController.lock();
327
- if (this.durationTimeout) {
328
- clearTimeout(this.durationTimeout);
315
+ const { durationTimeout, position, lastPresentedPosition } = this;
316
+ if (durationTimeout) {
317
+ clearTimeout(durationTimeout);
329
318
  }
330
- const dismissed = await dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation, this.position);
319
+ const dismissed = await dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation,
320
+ /**
321
+ * Fetch the cached position that was calculated back in the present
322
+ * animation. We always want to animate the dismiss from the same
323
+ * position the present stopped at, so the animation looks continuous.
324
+ */
325
+ {
326
+ position,
327
+ top: (_a = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.top) !== null && _a !== void 0 ? _a : '',
328
+ bottom: (_b = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.bottom) !== null && _b !== void 0 ? _b : '',
329
+ });
331
330
  if (dismissed) {
332
331
  this.delegateController.removeViewFromDom();
333
332
  this.revealContentToScreenReader = false;
334
333
  }
334
+ this.lastPresentedPosition = undefined;
335
335
  unlock();
336
336
  return dismissed;
337
337
  }
@@ -355,6 +355,37 @@ const Toast = /*@__PURE__*/ proxyCustomElement(class Toast extends HTMLElement {
355
355
  : [];
356
356
  return buttons;
357
357
  }
358
+ /**
359
+ * Returns the element specified by the positionAnchor prop,
360
+ * or undefined if prop's value is an ID string and the element
361
+ * is not found in the DOM.
362
+ */
363
+ getAnchorElement() {
364
+ const { position, positionAnchor, el } = this;
365
+ if (position === 'middle' && positionAnchor !== undefined) {
366
+ printIonWarning('The positionAnchor property is ignored when using position="middle".', this.el);
367
+ return undefined;
368
+ }
369
+ if (typeof positionAnchor === 'string') {
370
+ /**
371
+ * If the anchor is defined as an ID, find the element.
372
+ * We do this on every present so the toast doesn't need
373
+ * to account for the surrounding DOM changing since the
374
+ * last time it was presented.
375
+ */
376
+ const foundEl = document.getElementById(positionAnchor);
377
+ if (foundEl === null) {
378
+ printIonWarning(`An anchor element with an ID of "${positionAnchor}" was not found in the DOM.`, el);
379
+ return undefined;
380
+ }
381
+ return foundEl;
382
+ }
383
+ if (positionAnchor instanceof HTMLElement) {
384
+ return positionAnchor;
385
+ }
386
+ printIonWarning('Invalid positionAnchor value:', positionAnchor, el);
387
+ return undefined;
388
+ }
358
389
  async buttonClick(button) {
359
390
  const role = button.role;
360
391
  if (isCancel(role)) {
@@ -14,6 +14,7 @@ const index$1 = require('./index-0ee995e4.js');
14
14
  const ionicGlobal = require('./ionic-global-14a0604b.js');
15
15
  const helpers = require('./helpers-ea4ccbcb.js');
16
16
  const config = require('./config-d5882735.js');
17
+ const theme = require('./theme-fbc56b3b.js');
17
18
  const index$2 = require('./index-5121bb90.js');
18
19
  const overlays = require('./overlays-817dca17.js');
19
20
  require('./index-306a7476.js');
@@ -140,6 +141,7 @@ exports.componentOnReady = helpers.componentOnReady;
140
141
  exports.IonicSafeString = config.IonicSafeString;
141
142
  exports.getMode = config.getMode;
142
143
  exports.setupConfig = config.setupConfig;
144
+ exports.openURL = theme.openURL;
143
145
  exports.menuController = index$2.menuController;
144
146
  exports.actionSheetController = overlays.actionSheetController;
145
147
  exports.alertController = overlays.alertController;
@@ -175,6 +175,14 @@ const Alert = class {
175
175
  }
176
176
  onKeydown(ev) {
177
177
  const inputTypes = new Set(this.processedInputs.map((i) => i.type));
178
+ /**
179
+ * Based on keyboard navigation requirements, the
180
+ * checkbox should not respond to the enter keydown event.
181
+ */
182
+ if (inputTypes.has('checkbox') && ev.key === 'Enter') {
183
+ ev.preventDefault();
184
+ return;
185
+ }
178
186
  // The only inputs we want to navigate between using arrow keys are the radios
179
187
  // ignore the keydown event if it is not on a radio button
180
188
  if (!inputTypes.has('radio') ||
@@ -616,7 +616,7 @@ Developers can use the "legacy" property to continue using the legacy form marku
616
616
  }
617
617
  renderListbox() {
618
618
  const { disabled, inputId, isExpanded } = this;
619
- return (index.h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "listbox", "aria-expanded": `${isExpanded}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
619
+ return (index.h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
620
620
  }
621
621
  render() {
622
622
  const { legacyFormController } = this;