@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.
- package/components/alert.js +8 -0
- package/components/index.js +1 -0
- package/components/ion-select.js +1 -1
- package/components/ion-toast.js +144 -113
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/ion-alert.cjs.entry.js +8 -0
- package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
- package/dist/cjs/ion-toast.cjs.entry.js +163 -132
- package/dist/collection/components/alert/alert.js +8 -0
- package/dist/collection/components/alert/test/a11y/alert.e2e.js +11 -0
- package/dist/collection/components/select/select.js +1 -1
- package/dist/collection/components/toast/animations/ios.enter.js +1 -39
- package/dist/collection/components/toast/animations/ios.leave.js +4 -9
- package/dist/collection/components/toast/animations/md.enter.js +1 -40
- package/dist/collection/components/toast/animations/utils.js +85 -0
- package/dist/collection/components/toast/toast.js +58 -31
- package/dist/collection/index.js +1 -0
- package/dist/docs.json +3 -7
- package/dist/esm/index.js +1 -0
- package/dist/esm/ion-alert.entry.js +8 -0
- package/dist/esm/ion-select_3.entry.js +1 -1
- package/dist/esm/ion-toast.entry.js +144 -113
- package/dist/esm-es5/index.js +1 -1
- package/dist/esm-es5/ion-alert.entry.js +1 -1
- package/dist/esm-es5/ion-select_3.entry.js +1 -1
- package/dist/esm-es5/ion-toast.entry.js +1 -1
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-06c94b76.entry.js +4 -0
- package/dist/ionic/{p-2df840d9.system.entry.js → p-1e207aa7.system.entry.js} +1 -1
- package/dist/ionic/p-2bea5600.entry.js +4 -0
- package/dist/ionic/p-4e312f80.system.entry.js +4 -0
- package/dist/ionic/p-5f6605c4.entry.js +4 -0
- package/dist/ionic/{p-5d522814.system.entry.js → p-6cb04881.system.entry.js} +1 -1
- package/dist/ionic/p-6edbc09b.system.js +1 -1
- package/dist/ionic/p-8a1faf2c.system.js +4 -0
- package/dist/types/components/toast/animations/ios.leave.d.ts +2 -2
- package/dist/types/components/toast/animations/utils.d.ts +18 -0
- package/dist/types/components/toast/toast-interface.d.ts +8 -3
- package/dist/types/components/toast/toast.d.ts +12 -0
- package/dist/types/index.d.ts +1 -0
- package/hydrate/index.js +153 -114
- package/package.json +1 -1
- package/dist/ionic/p-1f448082.system.entry.js +0 -4
- package/dist/ionic/p-35d1c3bb.system.js +0 -4
- package/dist/ionic/p-8a26eaba.entry.js +0 -4
- package/dist/ionic/p-990aaa2f.entry.js +0 -4
- package/dist/ionic/p-c44645f2.entry.js +0 -4
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
7
7
|
|
|
8
|
-
const index$
|
|
8
|
+
const index$2 = require('./index-6f887430.js');
|
|
9
9
|
const config = require('./config-d5882735.js');
|
|
10
10
|
const helpers = require('./helpers-ea4ccbcb.js');
|
|
11
11
|
const lockController = require('./lock-controller-4ae2eb59.js');
|
|
12
|
-
const index$
|
|
12
|
+
const index$1 = require('./index-cc7dfb7c.js');
|
|
13
13
|
const overlays = require('./overlays-817dca17.js');
|
|
14
14
|
const theme = require('./theme-fbc56b3b.js');
|
|
15
15
|
const ionicGlobal = require('./ionic-global-14a0604b.js');
|
|
@@ -24,46 +24,9 @@ require('./hardware-back-button-b67c8e75.js');
|
|
|
24
24
|
const iosEnterAnimation = (baseEl, opts) => {
|
|
25
25
|
const baseAnimation = animation.createAnimation();
|
|
26
26
|
const wrapperAnimation = animation.createAnimation();
|
|
27
|
-
const { position,
|
|
27
|
+
const { position, top, bottom } = opts;
|
|
28
28
|
const root = helpers.getElementRoot(baseEl);
|
|
29
29
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
30
|
-
/**
|
|
31
|
-
* Start with a predefined offset from the edge the toast will be
|
|
32
|
-
* positioned relative to. By default, this will be the top edge
|
|
33
|
-
* of the screen.
|
|
34
|
-
*/
|
|
35
|
-
let offset = position === 'top' ? 10 : -10;
|
|
36
|
-
let top, bottom;
|
|
37
|
-
/**
|
|
38
|
-
* If positionAnchor is defined, add in the distance from the top
|
|
39
|
-
* of the screen to the target anchor edge. For position="top", the
|
|
40
|
-
* bottom anchor edge is targeted. For position="bottom", the top
|
|
41
|
-
* anchor edge is targeted.
|
|
42
|
-
*/
|
|
43
|
-
if (positionAnchor && index.win) {
|
|
44
|
-
const box = positionAnchor.getBoundingClientRect();
|
|
45
|
-
if (position === 'top') {
|
|
46
|
-
offset += box.bottom;
|
|
47
|
-
}
|
|
48
|
-
else if (position === 'bottom') {
|
|
49
|
-
/**
|
|
50
|
-
* Just box.top is the distance from the top edge of the screen
|
|
51
|
-
* to the top edge of the anchor. We want to calculate from the
|
|
52
|
-
* bottom edge of the screen instead.
|
|
53
|
-
*/
|
|
54
|
-
offset -= index.win.innerHeight - box.top;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* We don't include safe area here because that should already be
|
|
58
|
-
* accounted for when checking the position of the anchor.
|
|
59
|
-
*/
|
|
60
|
-
top = `${offset}px`;
|
|
61
|
-
bottom = `${offset}px`;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
|
|
65
|
-
bottom = `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`;
|
|
66
|
-
}
|
|
67
30
|
wrapperAnimation.addElement(wrapperEl);
|
|
68
31
|
switch (position) {
|
|
69
32
|
case 'top':
|
|
@@ -84,27 +47,22 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
84
47
|
/**
|
|
85
48
|
* iOS Toast Leave Animation
|
|
86
49
|
*/
|
|
87
|
-
const iosLeaveAnimation = (baseEl,
|
|
50
|
+
const iosLeaveAnimation = (baseEl, opts) => {
|
|
88
51
|
const baseAnimation = animation.createAnimation();
|
|
89
52
|
const wrapperAnimation = animation.createAnimation();
|
|
53
|
+
const { position, top, bottom } = opts;
|
|
90
54
|
const root = helpers.getElementRoot(baseEl);
|
|
91
55
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
92
56
|
wrapperAnimation.addElement(wrapperEl);
|
|
93
|
-
/**
|
|
94
|
-
* For top/bottom positions, we use to() instead of fromTo() so that if
|
|
95
|
-
* the positionAnchor prop was used, we don't need to recalculate the
|
|
96
|
-
* toast and/or anchor's position and duplicate work from the enter
|
|
97
|
-
* animation.
|
|
98
|
-
*/
|
|
99
57
|
switch (position) {
|
|
100
58
|
case 'top':
|
|
101
|
-
wrapperAnimation.
|
|
59
|
+
wrapperAnimation.fromTo('transform', `translateY(${top})`, 'translateY(-100%)');
|
|
102
60
|
break;
|
|
103
61
|
case 'middle':
|
|
104
62
|
wrapperAnimation.fromTo('opacity', 0.99, 0);
|
|
105
63
|
break;
|
|
106
64
|
default:
|
|
107
|
-
wrapperAnimation.
|
|
65
|
+
wrapperAnimation.fromTo('transform', `translateY(${bottom})`, 'translateY(100%)');
|
|
108
66
|
break;
|
|
109
67
|
}
|
|
110
68
|
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
|
|
@@ -116,47 +74,9 @@ const iosLeaveAnimation = (baseEl, position) => {
|
|
|
116
74
|
const mdEnterAnimation = (baseEl, opts) => {
|
|
117
75
|
const baseAnimation = animation.createAnimation();
|
|
118
76
|
const wrapperAnimation = animation.createAnimation();
|
|
119
|
-
const { position,
|
|
77
|
+
const { position, top, bottom } = opts;
|
|
120
78
|
const root = helpers.getElementRoot(baseEl);
|
|
121
79
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
122
|
-
/**
|
|
123
|
-
* Start with a predefined offset from the edge the toast will be
|
|
124
|
-
* positioned relative to. By default, this will be the top edge
|
|
125
|
-
* of the screen for position="top", or the bottom edge for
|
|
126
|
-
* position="bottom".
|
|
127
|
-
*/
|
|
128
|
-
let offset = 8;
|
|
129
|
-
let top, bottom;
|
|
130
|
-
/**
|
|
131
|
-
* If positionAnchor is defined, add in the distance from the target
|
|
132
|
-
* screen edge to the target anchor edge. For position="top", the
|
|
133
|
-
* bottom anchor edge is targeted. For position="bottom", the top
|
|
134
|
-
* anchor edge is targeted.
|
|
135
|
-
*/
|
|
136
|
-
if (positionAnchor && index.win) {
|
|
137
|
-
const box = positionAnchor.getBoundingClientRect();
|
|
138
|
-
if (position === 'top') {
|
|
139
|
-
offset += box.bottom;
|
|
140
|
-
}
|
|
141
|
-
else if (position === 'bottom') {
|
|
142
|
-
/**
|
|
143
|
-
* Just box.top is the distance from the top edge of the screen
|
|
144
|
-
* to the top edge of the anchor. We want to calculate from the
|
|
145
|
-
* bottom edge of the screen instead.
|
|
146
|
-
*/
|
|
147
|
-
offset += index.win.innerHeight - box.top;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* We don't include safe area here because that should already be
|
|
151
|
-
* accounted for when checking the position of the anchor.
|
|
152
|
-
*/
|
|
153
|
-
top = `${offset}px`;
|
|
154
|
-
bottom = `${offset}px`;
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
|
|
158
|
-
bottom = `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`;
|
|
159
|
-
}
|
|
160
80
|
wrapperAnimation.addElement(wrapperEl);
|
|
161
81
|
switch (position) {
|
|
162
82
|
case 'top':
|
|
@@ -188,21 +108,102 @@ const mdLeaveAnimation = (baseEl) => {
|
|
|
188
108
|
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
|
|
189
109
|
};
|
|
190
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Calculate the CSS top and bottom position of the toast, to be used
|
|
113
|
+
* as starting points for the animation keyframes.
|
|
114
|
+
*
|
|
115
|
+
* Note that MD animates bottom-positioned toasts using style.bottom,
|
|
116
|
+
* which calculates from the bottom edge of the screen, while iOS uses
|
|
117
|
+
* translateY, which calculates from the top edge of the screen. This
|
|
118
|
+
* is why the bottom calculates differ slightly between modes.
|
|
119
|
+
*
|
|
120
|
+
* @param position The value of the toast's position prop.
|
|
121
|
+
* @param positionAnchor The element the toast should be anchored to,
|
|
122
|
+
* if applicable.
|
|
123
|
+
* @param mode The toast component's mode (md, ios, etc).
|
|
124
|
+
* @param toast A reference to the toast element itself.
|
|
125
|
+
*/
|
|
126
|
+
function getAnimationPosition(position, positionAnchor, mode, toast) {
|
|
127
|
+
/**
|
|
128
|
+
* Start with a predefined offset from the edge the toast will be
|
|
129
|
+
* positioned relative to, whether on the screen or anchor element.
|
|
130
|
+
*/
|
|
131
|
+
let offset;
|
|
132
|
+
if (mode === 'md') {
|
|
133
|
+
offset = 8;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
offset = position === 'top' ? 10 : -10;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* If positionAnchor is defined, add in the distance from the target
|
|
140
|
+
* screen edge to the target anchor edge. For position="top", the
|
|
141
|
+
* bottom anchor edge is targeted. For position="bottom", the top
|
|
142
|
+
* anchor edge is targeted.
|
|
143
|
+
*/
|
|
144
|
+
if (positionAnchor && index.win) {
|
|
145
|
+
warnIfAnchorIsHidden(positionAnchor, toast);
|
|
146
|
+
const box = positionAnchor.getBoundingClientRect();
|
|
147
|
+
if (position === 'top') {
|
|
148
|
+
offset += box.bottom;
|
|
149
|
+
}
|
|
150
|
+
else if (position === 'bottom') {
|
|
151
|
+
/**
|
|
152
|
+
* Just box.top is the distance from the top edge of the screen
|
|
153
|
+
* to the top edge of the anchor. We want to calculate from the
|
|
154
|
+
* bottom edge of the screen instead.
|
|
155
|
+
*/
|
|
156
|
+
if (mode === 'md') {
|
|
157
|
+
offset += index.win.innerHeight - box.top;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
offset -= index.win.innerHeight - box.top;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* We don't include safe area here because that should already be
|
|
165
|
+
* accounted for when checking the position of the anchor.
|
|
166
|
+
*/
|
|
167
|
+
return {
|
|
168
|
+
top: `${offset}px`,
|
|
169
|
+
bottom: `${offset}px`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
return {
|
|
174
|
+
top: `calc(${offset}px + var(--ion-safe-area-top, 0px))`,
|
|
175
|
+
bottom: mode === 'md'
|
|
176
|
+
? `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`
|
|
177
|
+
: `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* If the anchor element is hidden, getBoundingClientRect()
|
|
183
|
+
* will return all 0s for it, which can cause unexpected
|
|
184
|
+
* results in the position calculation when animating.
|
|
185
|
+
*/
|
|
186
|
+
function warnIfAnchorIsHidden(positionAnchor, toast) {
|
|
187
|
+
if (positionAnchor.offsetParent === null) {
|
|
188
|
+
index$1.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);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
191
192
|
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}}";
|
|
192
193
|
|
|
193
194
|
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)}}";
|
|
194
195
|
|
|
195
196
|
const Toast = class {
|
|
196
197
|
constructor(hostRef) {
|
|
197
|
-
index$
|
|
198
|
-
this.didPresent = index$
|
|
199
|
-
this.willPresent = index$
|
|
200
|
-
this.willDismiss = index$
|
|
201
|
-
this.didDismiss = index$
|
|
202
|
-
this.didPresentShorthand = index$
|
|
203
|
-
this.willPresentShorthand = index$
|
|
204
|
-
this.willDismissShorthand = index$
|
|
205
|
-
this.didDismissShorthand = index$
|
|
198
|
+
index$2.registerInstance(this, hostRef);
|
|
199
|
+
this.didPresent = index$2.createEvent(this, "ionToastDidPresent", 7);
|
|
200
|
+
this.willPresent = index$2.createEvent(this, "ionToastWillPresent", 7);
|
|
201
|
+
this.willDismiss = index$2.createEvent(this, "ionToastWillDismiss", 7);
|
|
202
|
+
this.didDismiss = index$2.createEvent(this, "ionToastDidDismiss", 7);
|
|
203
|
+
this.didPresentShorthand = index$2.createEvent(this, "didPresent", 7);
|
|
204
|
+
this.willPresentShorthand = index$2.createEvent(this, "willPresent", 7);
|
|
205
|
+
this.willDismissShorthand = index$2.createEvent(this, "willDismiss", 7);
|
|
206
|
+
this.didDismissShorthand = index$2.createEvent(this, "didDismiss", 7);
|
|
206
207
|
this.delegateController = overlays.createDelegateController(this);
|
|
207
208
|
this.lockController = lockController.createLockController();
|
|
208
209
|
this.triggerController = overlays.createTriggerController();
|
|
@@ -277,32 +278,18 @@ const Toast = class {
|
|
|
277
278
|
async present() {
|
|
278
279
|
const unlock = await this.lockController.lock();
|
|
279
280
|
await this.delegateController.attachViewToDom();
|
|
280
|
-
const {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
* We do this on every present so the toast doesn't need
|
|
289
|
-
* to account for the surrounding DOM changing since the
|
|
290
|
-
* last time it was presented.
|
|
291
|
-
*/
|
|
292
|
-
const foundEl = document.getElementById(positionAnchor);
|
|
293
|
-
if (foundEl === null) {
|
|
294
|
-
index$2.printIonWarning(`An anchor element with an ID of ${positionAnchor} was not found in the DOM.`, this.el);
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
anchor = foundEl;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
anchor = positionAnchor;
|
|
302
|
-
}
|
|
281
|
+
const { el, position } = this;
|
|
282
|
+
const anchor = this.getAnchorElement();
|
|
283
|
+
const animationPosition = getAnimationPosition(position, anchor, ionicGlobal.getIonMode(this), el);
|
|
284
|
+
/**
|
|
285
|
+
* Cache the calculated position of the toast, so we can re-use it
|
|
286
|
+
* in the dismiss animation.
|
|
287
|
+
*/
|
|
288
|
+
this.lastPresentedPosition = animationPosition;
|
|
303
289
|
await overlays.present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, {
|
|
304
290
|
position,
|
|
305
|
-
|
|
291
|
+
top: animationPosition.top,
|
|
292
|
+
bottom: animationPosition.bottom,
|
|
306
293
|
});
|
|
307
294
|
/**
|
|
308
295
|
* Content is revealed to screen readers after
|
|
@@ -325,15 +312,28 @@ const Toast = class {
|
|
|
325
312
|
* Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
|
|
326
313
|
*/
|
|
327
314
|
async dismiss(data, role) {
|
|
315
|
+
var _a, _b;
|
|
328
316
|
const unlock = await this.lockController.lock();
|
|
329
|
-
|
|
330
|
-
|
|
317
|
+
const { durationTimeout, position, lastPresentedPosition } = this;
|
|
318
|
+
if (durationTimeout) {
|
|
319
|
+
clearTimeout(durationTimeout);
|
|
331
320
|
}
|
|
332
|
-
const dismissed = await overlays.dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation,
|
|
321
|
+
const dismissed = await overlays.dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation,
|
|
322
|
+
/**
|
|
323
|
+
* Fetch the cached position that was calculated back in the present
|
|
324
|
+
* animation. We always want to animate the dismiss from the same
|
|
325
|
+
* position the present stopped at, so the animation looks continuous.
|
|
326
|
+
*/
|
|
327
|
+
{
|
|
328
|
+
position,
|
|
329
|
+
top: (_a = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.top) !== null && _a !== void 0 ? _a : '',
|
|
330
|
+
bottom: (_b = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.bottom) !== null && _b !== void 0 ? _b : '',
|
|
331
|
+
});
|
|
333
332
|
if (dismissed) {
|
|
334
333
|
this.delegateController.removeViewFromDom();
|
|
335
334
|
this.revealContentToScreenReader = false;
|
|
336
335
|
}
|
|
336
|
+
this.lastPresentedPosition = undefined;
|
|
337
337
|
unlock();
|
|
338
338
|
return dismissed;
|
|
339
339
|
}
|
|
@@ -357,6 +357,37 @@ const Toast = class {
|
|
|
357
357
|
: [];
|
|
358
358
|
return buttons;
|
|
359
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Returns the element specified by the positionAnchor prop,
|
|
362
|
+
* or undefined if prop's value is an ID string and the element
|
|
363
|
+
* is not found in the DOM.
|
|
364
|
+
*/
|
|
365
|
+
getAnchorElement() {
|
|
366
|
+
const { position, positionAnchor, el } = this;
|
|
367
|
+
if (position === 'middle' && positionAnchor !== undefined) {
|
|
368
|
+
index$1.printIonWarning('The positionAnchor property is ignored when using position="middle".', this.el);
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
if (typeof positionAnchor === 'string') {
|
|
372
|
+
/**
|
|
373
|
+
* If the anchor is defined as an ID, find the element.
|
|
374
|
+
* We do this on every present so the toast doesn't need
|
|
375
|
+
* to account for the surrounding DOM changing since the
|
|
376
|
+
* last time it was presented.
|
|
377
|
+
*/
|
|
378
|
+
const foundEl = document.getElementById(positionAnchor);
|
|
379
|
+
if (foundEl === null) {
|
|
380
|
+
index$1.printIonWarning(`An anchor element with an ID of "${positionAnchor}" was not found in the DOM.`, el);
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
return foundEl;
|
|
384
|
+
}
|
|
385
|
+
if (positionAnchor instanceof HTMLElement) {
|
|
386
|
+
return positionAnchor;
|
|
387
|
+
}
|
|
388
|
+
index$1.printIonWarning('Invalid positionAnchor value:', positionAnchor, el);
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
360
391
|
async buttonClick(button) {
|
|
361
392
|
const role = button.role;
|
|
362
393
|
if (overlays.isCancel(role)) {
|
|
@@ -394,7 +425,7 @@ const Toast = class {
|
|
|
394
425
|
'toast-button-group': true,
|
|
395
426
|
[`toast-button-group-${side}`]: true,
|
|
396
427
|
};
|
|
397
|
-
return (index$
|
|
428
|
+
return (index$2.h("div", { class: buttonGroupsClasses }, buttons.map((b) => (index$2.h("button", Object.assign({}, b.htmlAttributes, { type: "button", class: buttonClass(b), tabIndex: 0, onClick: () => this.buttonClick(b), part: buttonPart(b) }), index$2.h("div", { class: "toast-button-inner" }, b.icon && (index$2.h("ion-icon", { "aria-hidden": "true", icon: b.icon, slot: b.text === undefined ? 'icon-only' : undefined, class: "toast-button-icon" })), b.text), mode === 'md' && (index$2.h("ion-ripple-effect", { type: b.icon !== undefined && b.text === undefined ? 'unbounded' : 'bounded' })))))));
|
|
398
429
|
}
|
|
399
430
|
/**
|
|
400
431
|
* Render the `message` property.
|
|
@@ -404,9 +435,9 @@ const Toast = class {
|
|
|
404
435
|
renderToastMessage(key, ariaHidden = null) {
|
|
405
436
|
const { customHTMLEnabled, message } = this;
|
|
406
437
|
if (customHTMLEnabled) {
|
|
407
|
-
return (index$
|
|
438
|
+
return (index$2.h("div", { key: key, "aria-hidden": ariaHidden, class: "toast-message", part: "message", innerHTML: config.sanitizeDOMString(message) }));
|
|
408
439
|
}
|
|
409
|
-
return (index$
|
|
440
|
+
return (index$2.h("div", { key: key, "aria-hidden": ariaHidden, class: "toast-message", part: "message" }, message));
|
|
410
441
|
}
|
|
411
442
|
/**
|
|
412
443
|
* Render the `header` property.
|
|
@@ -414,7 +445,7 @@ const Toast = class {
|
|
|
414
445
|
* @param ariaHidden - If "true" then content will be hidden from screen readers.
|
|
415
446
|
*/
|
|
416
447
|
renderHeader(key, ariaHidden = null) {
|
|
417
|
-
return (index$
|
|
448
|
+
return (index$2.h("div", { key: key, class: "toast-header", "aria-hidden": ariaHidden, part: "header" }, this.header));
|
|
418
449
|
}
|
|
419
450
|
render() {
|
|
420
451
|
const { layout, el, revealContentToScreenReader, header, message } = this;
|
|
@@ -432,13 +463,13 @@ const Toast = class {
|
|
|
432
463
|
* used with one type of button.
|
|
433
464
|
*/
|
|
434
465
|
if (layout === 'stacked' && startButtons.length > 0 && endButtons.length > 0) {
|
|
435
|
-
index$
|
|
466
|
+
index$1.printIonWarning('This toast is using start and end buttons with the stacked toast layout. We recommend following the best practice of using either start or end buttons with the stacked toast layout.', el);
|
|
436
467
|
}
|
|
437
|
-
return (index$
|
|
468
|
+
return (index$2.h(index$2.Host, Object.assign({ tabindex: "-1" }, this.htmlAttributes, { style: {
|
|
438
469
|
zIndex: `${60000 + this.overlayIndex}`,
|
|
439
|
-
}, class: theme.createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true }, theme.getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), index$
|
|
470
|
+
}, class: theme.createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true }, theme.getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), index$2.h("div", { class: wrapperClass }, index$2.h("div", { class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (index$2.h("ion-icon", { class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), index$2.h("div", { class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
|
|
440
471
|
}
|
|
441
|
-
get el() { return index$
|
|
472
|
+
get el() { return index$2.getElement(this); }
|
|
442
473
|
static get watchers() { return {
|
|
443
474
|
"isOpen": ["onIsOpenChange"],
|
|
444
475
|
"trigger": ["triggerChanged"]
|
|
@@ -73,6 +73,14 @@ export class Alert {
|
|
|
73
73
|
}
|
|
74
74
|
onKeydown(ev) {
|
|
75
75
|
const inputTypes = new Set(this.processedInputs.map((i) => i.type));
|
|
76
|
+
/**
|
|
77
|
+
* Based on keyboard navigation requirements, the
|
|
78
|
+
* checkbox should not respond to the enter keydown event.
|
|
79
|
+
*/
|
|
80
|
+
if (inputTypes.has('checkbox') && ev.key === 'Enter') {
|
|
81
|
+
ev.preventDefault();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
76
84
|
// The only inputs we want to navigate between using arrow keys are the radios
|
|
77
85
|
// ignore the keydown event if it is not on a radio button
|
|
78
86
|
if (!inputTypes.has('radio') ||
|
|
@@ -54,5 +54,16 @@ configs({ directions: ['ltr'] }).forEach(({ config, title }) => {
|
|
|
54
54
|
await expect(alertButton).toHaveAttribute('aria-labelledby', 'close-label');
|
|
55
55
|
await expect(alertButton).toHaveAttribute('aria-label', 'close button');
|
|
56
56
|
});
|
|
57
|
+
test('should not toggle the checkbox when pressing the Enter key', async ({ page }) => {
|
|
58
|
+
const didPresent = await page.spyOnEvent('ionAlertDidPresent');
|
|
59
|
+
const button = page.locator('#checkbox');
|
|
60
|
+
await button.click();
|
|
61
|
+
await didPresent.next();
|
|
62
|
+
const alertCheckbox = page.locator('ion-alert .alert-checkbox');
|
|
63
|
+
const ariaChecked = await alertCheckbox.getAttribute('aria-checked');
|
|
64
|
+
await expect(alertCheckbox).toHaveAttribute('aria-checked', ariaChecked);
|
|
65
|
+
await alertCheckbox.press('Enter');
|
|
66
|
+
await expect(alertCheckbox).toHaveAttribute('aria-checked', ariaChecked);
|
|
67
|
+
});
|
|
57
68
|
});
|
|
58
69
|
});
|
|
@@ -642,7 +642,7 @@ Developers can use the "legacy" property to continue using the legacy form marku
|
|
|
642
642
|
}
|
|
643
643
|
renderListbox() {
|
|
644
644
|
const { disabled, inputId, isExpanded } = this;
|
|
645
|
-
return (h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "
|
|
645
|
+
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) }));
|
|
646
646
|
}
|
|
647
647
|
render() {
|
|
648
648
|
const { legacyFormController } = this;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { createAnimation } from "../../../utils/animation/animation";
|
|
5
|
-
import { win } from "../../../utils/browser/index";
|
|
6
5
|
import { getElementRoot } from "../../../utils/helpers";
|
|
7
6
|
/**
|
|
8
7
|
* iOS Toast Enter Animation
|
|
@@ -10,46 +9,9 @@ import { getElementRoot } from "../../../utils/helpers";
|
|
|
10
9
|
export const iosEnterAnimation = (baseEl, opts) => {
|
|
11
10
|
const baseAnimation = createAnimation();
|
|
12
11
|
const wrapperAnimation = createAnimation();
|
|
13
|
-
const { position,
|
|
12
|
+
const { position, top, bottom } = opts;
|
|
14
13
|
const root = getElementRoot(baseEl);
|
|
15
14
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
16
|
-
/**
|
|
17
|
-
* Start with a predefined offset from the edge the toast will be
|
|
18
|
-
* positioned relative to. By default, this will be the top edge
|
|
19
|
-
* of the screen.
|
|
20
|
-
*/
|
|
21
|
-
let offset = position === 'top' ? 10 : -10;
|
|
22
|
-
let top, bottom;
|
|
23
|
-
/**
|
|
24
|
-
* If positionAnchor is defined, add in the distance from the top
|
|
25
|
-
* of the screen to the target anchor edge. For position="top", the
|
|
26
|
-
* bottom anchor edge is targeted. For position="bottom", the top
|
|
27
|
-
* anchor edge is targeted.
|
|
28
|
-
*/
|
|
29
|
-
if (positionAnchor && win) {
|
|
30
|
-
const box = positionAnchor.getBoundingClientRect();
|
|
31
|
-
if (position === 'top') {
|
|
32
|
-
offset += box.bottom;
|
|
33
|
-
}
|
|
34
|
-
else if (position === 'bottom') {
|
|
35
|
-
/**
|
|
36
|
-
* Just box.top is the distance from the top edge of the screen
|
|
37
|
-
* to the top edge of the anchor. We want to calculate from the
|
|
38
|
-
* bottom edge of the screen instead.
|
|
39
|
-
*/
|
|
40
|
-
offset -= win.innerHeight - box.top;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* We don't include safe area here because that should already be
|
|
44
|
-
* accounted for when checking the position of the anchor.
|
|
45
|
-
*/
|
|
46
|
-
top = `${offset}px`;
|
|
47
|
-
bottom = `${offset}px`;
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
|
|
51
|
-
bottom = `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`;
|
|
52
|
-
}
|
|
53
15
|
wrapperAnimation.addElement(wrapperEl);
|
|
54
16
|
switch (position) {
|
|
55
17
|
case 'top':
|
|
@@ -6,27 +6,22 @@ import { getElementRoot } from "../../../utils/helpers";
|
|
|
6
6
|
/**
|
|
7
7
|
* iOS Toast Leave Animation
|
|
8
8
|
*/
|
|
9
|
-
export const iosLeaveAnimation = (baseEl,
|
|
9
|
+
export const iosLeaveAnimation = (baseEl, opts) => {
|
|
10
10
|
const baseAnimation = createAnimation();
|
|
11
11
|
const wrapperAnimation = createAnimation();
|
|
12
|
+
const { position, top, bottom } = opts;
|
|
12
13
|
const root = getElementRoot(baseEl);
|
|
13
14
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
14
15
|
wrapperAnimation.addElement(wrapperEl);
|
|
15
|
-
/**
|
|
16
|
-
* For top/bottom positions, we use to() instead of fromTo() so that if
|
|
17
|
-
* the positionAnchor prop was used, we don't need to recalculate the
|
|
18
|
-
* toast and/or anchor's position and duplicate work from the enter
|
|
19
|
-
* animation.
|
|
20
|
-
*/
|
|
21
16
|
switch (position) {
|
|
22
17
|
case 'top':
|
|
23
|
-
wrapperAnimation.
|
|
18
|
+
wrapperAnimation.fromTo('transform', `translateY(${top})`, 'translateY(-100%)');
|
|
24
19
|
break;
|
|
25
20
|
case 'middle':
|
|
26
21
|
wrapperAnimation.fromTo('opacity', 0.99, 0);
|
|
27
22
|
break;
|
|
28
23
|
default:
|
|
29
|
-
wrapperAnimation.
|
|
24
|
+
wrapperAnimation.fromTo('transform', `translateY(${bottom})`, 'translateY(100%)');
|
|
30
25
|
break;
|
|
31
26
|
}
|
|
32
27
|
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { createAnimation } from "../../../utils/animation/animation";
|
|
5
|
-
import { win } from "../../../utils/browser/index";
|
|
6
5
|
import { getElementRoot } from "../../../utils/helpers";
|
|
7
6
|
/**
|
|
8
7
|
* MD Toast Enter Animation
|
|
@@ -10,47 +9,9 @@ import { getElementRoot } from "../../../utils/helpers";
|
|
|
10
9
|
export const mdEnterAnimation = (baseEl, opts) => {
|
|
11
10
|
const baseAnimation = createAnimation();
|
|
12
11
|
const wrapperAnimation = createAnimation();
|
|
13
|
-
const { position,
|
|
12
|
+
const { position, top, bottom } = opts;
|
|
14
13
|
const root = getElementRoot(baseEl);
|
|
15
14
|
const wrapperEl = root.querySelector('.toast-wrapper');
|
|
16
|
-
/**
|
|
17
|
-
* Start with a predefined offset from the edge the toast will be
|
|
18
|
-
* positioned relative to. By default, this will be the top edge
|
|
19
|
-
* of the screen for position="top", or the bottom edge for
|
|
20
|
-
* position="bottom".
|
|
21
|
-
*/
|
|
22
|
-
let offset = 8;
|
|
23
|
-
let top, bottom;
|
|
24
|
-
/**
|
|
25
|
-
* If positionAnchor is defined, add in the distance from the target
|
|
26
|
-
* screen edge to the target anchor edge. For position="top", the
|
|
27
|
-
* bottom anchor edge is targeted. For position="bottom", the top
|
|
28
|
-
* anchor edge is targeted.
|
|
29
|
-
*/
|
|
30
|
-
if (positionAnchor && win) {
|
|
31
|
-
const box = positionAnchor.getBoundingClientRect();
|
|
32
|
-
if (position === 'top') {
|
|
33
|
-
offset += box.bottom;
|
|
34
|
-
}
|
|
35
|
-
else if (position === 'bottom') {
|
|
36
|
-
/**
|
|
37
|
-
* Just box.top is the distance from the top edge of the screen
|
|
38
|
-
* to the top edge of the anchor. We want to calculate from the
|
|
39
|
-
* bottom edge of the screen instead.
|
|
40
|
-
*/
|
|
41
|
-
offset += win.innerHeight - box.top;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* We don't include safe area here because that should already be
|
|
45
|
-
* accounted for when checking the position of the anchor.
|
|
46
|
-
*/
|
|
47
|
-
top = `${offset}px`;
|
|
48
|
-
bottom = `${offset}px`;
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
top = `calc(${offset}px + var(--ion-safe-area-top, 0px))`;
|
|
52
|
-
bottom = `calc(${offset}px + var(--ion-safe-area-bottom, 0px))`;
|
|
53
|
-
}
|
|
54
15
|
wrapperAnimation.addElement(wrapperEl);
|
|
55
16
|
switch (position) {
|
|
56
17
|
case 'top':
|