UNPKG

21.1 kBJavaScriptView Raw
1/*!
2 * (C) Ionic http://ionicframework.com - MIT License
3 */
4import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
5import { b as getIonMode } from './ionic-global.js';
6import { i as isCancel, e as prepareOverlay, d as present, f as dismiss, g as eventMethod, s as safeCall } from './overlays.js';
7import { s as sanitizeDOMString } from './index3.js';
8import { g as getClassMap, c as createColorClasses } from './theme.js';
9import { c as createAnimation } from './animation.js';
10import { g as getElementRoot } from './helpers.js';
11import { d as defineCustomElement$3 } from './icon.js';
12import { d as defineCustomElement$2 } from './ripple-effect.js';
13
14/**
15 * iOS Toast Enter Animation
16 */
17const iosEnterAnimation = (baseEl, position) => {
18 const baseAnimation = createAnimation();
19 const wrapperAnimation = createAnimation();
20 const root = getElementRoot(baseEl);
21 const wrapperEl = root.querySelector('.toast-wrapper');
22 const bottom = `calc(-10px - var(--ion-safe-area-bottom, 0px))`;
23 const top = `calc(10px + var(--ion-safe-area-top, 0px))`;
24 wrapperAnimation.addElement(wrapperEl);
25 switch (position) {
26 case 'top':
27 wrapperAnimation.fromTo('transform', 'translateY(-100%)', `translateY(${top})`);
28 break;
29 case 'middle':
30 const topPosition = Math.floor(baseEl.clientHeight / 2 - wrapperEl.clientHeight / 2);
31 wrapperEl.style.top = `${topPosition}px`;
32 wrapperAnimation.fromTo('opacity', 0.01, 1);
33 break;
34 default:
35 wrapperAnimation.fromTo('transform', 'translateY(100%)', `translateY(${bottom})`);
36 break;
37 }
38 return baseAnimation
39 .easing('cubic-bezier(.155,1.105,.295,1.12)')
40 .duration(400)
41 .addAnimation(wrapperAnimation);
42};
43
44/**
45 * iOS Toast Leave Animation
46 */
47const iosLeaveAnimation = (baseEl, position) => {
48 const baseAnimation = createAnimation();
49 const wrapperAnimation = createAnimation();
50 const root = getElementRoot(baseEl);
51 const wrapperEl = root.querySelector('.toast-wrapper');
52 const bottom = `calc(-10px - var(--ion-safe-area-bottom, 0px))`;
53 const top = `calc(10px + var(--ion-safe-area-top, 0px))`;
54 wrapperAnimation.addElement(wrapperEl);
55 switch (position) {
56 case 'top':
57 wrapperAnimation.fromTo('transform', `translateY(${top})`, 'translateY(-100%)');
58 break;
59 case 'middle':
60 wrapperAnimation.fromTo('opacity', 0.99, 0);
61 break;
62 default:
63 wrapperAnimation.fromTo('transform', `translateY(${bottom})`, 'translateY(100%)');
64 break;
65 }
66 return baseAnimation
67 .easing('cubic-bezier(.36,.66,.04,1)')
68 .duration(300)
69 .addAnimation(wrapperAnimation);
70};
71
72/**
73 * MD Toast Enter Animation
74 */
75const mdEnterAnimation = (baseEl, position) => {
76 const baseAnimation = createAnimation();
77 const wrapperAnimation = createAnimation();
78 const root = getElementRoot(baseEl);
79 const wrapperEl = root.querySelector('.toast-wrapper');
80 const bottom = `calc(8px + var(--ion-safe-area-bottom, 0px))`;
81 const top = `calc(8px + var(--ion-safe-area-top, 0px))`;
82 wrapperAnimation.addElement(wrapperEl);
83 switch (position) {
84 case 'top':
85 wrapperEl.style.top = top;
86 wrapperAnimation.fromTo('opacity', 0.01, 1);
87 break;
88 case 'middle':
89 const topPosition = Math.floor(baseEl.clientHeight / 2 - wrapperEl.clientHeight / 2);
90 wrapperEl.style.top = `${topPosition}px`;
91 wrapperAnimation.fromTo('opacity', 0.01, 1);
92 break;
93 default:
94 wrapperEl.style.bottom = bottom;
95 wrapperAnimation.fromTo('opacity', 0.01, 1);
96 break;
97 }
98 return baseAnimation
99 .easing('cubic-bezier(.36,.66,.04,1)')
100 .duration(400)
101 .addAnimation(wrapperAnimation);
102};
103
104/**
105 * md Toast Leave Animation
106 */
107const mdLeaveAnimation = (baseEl) => {
108 const baseAnimation = createAnimation();
109 const wrapperAnimation = createAnimation();
110 const root = getElementRoot(baseEl);
111 const wrapperEl = root.querySelector('.toast-wrapper');
112 wrapperAnimation
113 .addElement(wrapperEl)
114 .fromTo('opacity', 0.99, 0);
115 return baseAnimation
116 .easing('cubic-bezier(.36,.66,.04,1)')
117 .duration(300)
118 .addAnimation(wrapperAnimation);
119};
120
121const 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;left:0;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}:host-context([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);left:var(--start);right:var(--end);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)}[dir=rtl] .toast-wrapper,:host-context([dir=rtl]) .toast-wrapper{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-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{margin-left:16px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-icon{margin-left:unset;-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-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{margin-left:auto;margin-right:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;z-index:10}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-wrapper{margin-left:unset;margin-right:unset;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto}}@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)}}.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{padding-left:15px;padding-right:15px;padding-top:15px;padding-bottom:15px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-content{padding-left:unset;padding-right:unset;-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px}}.toast-header{margin-bottom:2px;font-weight:500}.toast-button{padding-left:15px;padding-right: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}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-button{padding-left:unset;padding-right:unset;-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px}}.toast-button.ion-activated{opacity:0.4}@media (any-hover: hover){.toast-button:hover{opacity:0.6}}";
122
123const 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;left:0;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}:host-context([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);left:var(--start);right:var(--end);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)}[dir=rtl] .toast-wrapper,:host-context([dir=rtl]) .toast-wrapper{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-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{margin-left:16px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-icon{margin-left:unset;-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-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{margin-left:auto;margin-right:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;opacity:0.01;z-index:10}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-wrapper{margin-left:unset;margin-right:unset;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto}}.toast-content{padding-left:16px;padding-right:16px;padding-top:14px;padding-bottom:14px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-content{padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}.toast-header{margin-bottom:2px;font-weight:500;line-height:20px}.toast-message{line-height:20px}.toast-button-group-start{margin-left:8px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-button-group-start{margin-left:unset;-webkit-margin-start:8px;margin-inline-start:8px}}.toast-button-group-end{margin-right:8px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-button-group-end{margin-right:unset;-webkit-margin-end:8px;margin-inline-end:8px}}.toast-button{padding-left:15px;padding-right: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}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-button{padding-left:unset;padding-right:unset;-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px}}.toast-button-cancel{color:var(--ion-color-step-100, #e6e6e6)}.toast-button-icon-only{border-radius:50%;padding-left:9px;padding-right:9px;padding-top:9px;padding-bottom:9px;width:36px;height:36px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.toast-button-icon-only{padding-left:unset;padding-right:unset;-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px}}@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)}}";
124
125const Toast = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
126 constructor() {
127 super();
128 this.__registerHost();
129 this.__attachShadow();
130 this.didPresent = createEvent(this, "ionToastDidPresent", 7);
131 this.willPresent = createEvent(this, "ionToastWillPresent", 7);
132 this.willDismiss = createEvent(this, "ionToastWillDismiss", 7);
133 this.didDismiss = createEvent(this, "ionToastDidDismiss", 7);
134 this.presented = false;
135 /**
136 * How many milliseconds to wait before hiding the toast. By default, it will show
137 * until `dismiss()` is called.
138 */
139 this.duration = 0;
140 /**
141 * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
142 */
143 this.keyboardClose = false;
144 /**
145 * The position of the toast on the screen.
146 */
147 this.position = 'bottom';
148 /**
149 * If `true`, the toast will be translucent.
150 * Only applies when the mode is `"ios"` and the device supports
151 * [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
152 */
153 this.translucent = false;
154 /**
155 * If `true`, the toast will animate.
156 */
157 this.animated = true;
158 this.dispatchCancelHandler = (ev) => {
159 const role = ev.detail.role;
160 if (isCancel(role)) {
161 const cancelButton = this.getButtons().find(b => b.role === 'cancel');
162 this.callButtonHandler(cancelButton);
163 }
164 };
165 }
166 connectedCallback() {
167 prepareOverlay(this.el);
168 }
169 /**
170 * Present the toast overlay after it has been created.
171 */
172 async present() {
173 await present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, this.position);
174 if (this.duration > 0) {
175 this.durationTimeout = setTimeout(() => this.dismiss(undefined, 'timeout'), this.duration);
176 }
177 }
178 /**
179 * Dismiss the toast overlay after it has been presented.
180 *
181 * @param data Any data to emit in the dismiss events.
182 * @param role The role of the element that is dismissing the toast.
183 * This can be useful in a button handler for determining which button was
184 * clicked to dismiss the toast.
185 * Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
186 */
187 dismiss(data, role) {
188 if (this.durationTimeout) {
189 clearTimeout(this.durationTimeout);
190 }
191 return dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation, this.position);
192 }
193 /**
194 * Returns a promise that resolves when the toast did dismiss.
195 */
196 onDidDismiss() {
197 return eventMethod(this.el, 'ionToastDidDismiss');
198 }
199 /**
200 * Returns a promise that resolves when the toast will dismiss.
201 */
202 onWillDismiss() {
203 return eventMethod(this.el, 'ionToastWillDismiss');
204 }
205 getButtons() {
206 const buttons = this.buttons
207 ? this.buttons.map(b => {
208 return (typeof b === 'string')
209 ? { text: b }
210 : b;
211 })
212 : [];
213 return buttons;
214 }
215 async buttonClick(button) {
216 const role = button.role;
217 if (isCancel(role)) {
218 return this.dismiss(undefined, role);
219 }
220 const shouldDismiss = await this.callButtonHandler(button);
221 if (shouldDismiss) {
222 return this.dismiss(undefined, role);
223 }
224 return Promise.resolve();
225 }
226 async callButtonHandler(button) {
227 if (button && button.handler) {
228 // a handler has been provided, execute it
229 // pass the handler the values from the inputs
230 try {
231 const rtn = await safeCall(button.handler);
232 if (rtn === false) {
233 // if the return value of the handler is false then do not dismiss
234 return false;
235 }
236 }
237 catch (e) {
238 console.error(e);
239 }
240 }
241 return true;
242 }
243 renderButtons(buttons, side) {
244 if (buttons.length === 0) {
245 return;
246 }
247 const mode = getIonMode(this);
248 const buttonGroupsClasses = {
249 'toast-button-group': true,
250 [`toast-button-group-${side}`]: true
251 };
252 return (h("div", { class: buttonGroupsClasses }, buttons.map(b => h("button", { type: "button", class: buttonClass(b), tabIndex: 0, onClick: () => this.buttonClick(b), part: "button" }, h("div", { class: "toast-button-inner" }, b.icon &&
253 h("ion-icon", { icon: b.icon, slot: b.text === undefined ? 'icon-only' : undefined, class: "toast-button-icon" }), b.text), mode === 'md' && h("ion-ripple-effect", { type: b.icon !== undefined && b.text === undefined ? 'unbounded' : 'bounded' })))));
254 }
255 render() {
256 const allButtons = this.getButtons();
257 const startButtons = allButtons.filter(b => b.side === 'start');
258 const endButtons = allButtons.filter(b => b.side !== 'start');
259 const mode = getIonMode(this);
260 const wrapperClass = {
261 'toast-wrapper': true,
262 [`toast-${this.position}`]: true
263 };
264 const role = allButtons.length > 0 ? 'dialog' : 'status';
265 return (h(Host, Object.assign({ "aria-live": "polite", "aria-atomic": "true", role: role, tabindex: "-1" }, this.htmlAttributes, { style: {
266 zIndex: `${60000 + this.overlayIndex}`,
267 }, class: createColorClasses(this.color, Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), h("div", { class: wrapperClass }, h("div", { class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined &&
268 h("ion-icon", { class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" }), h("div", { class: "toast-content" }, this.header !== undefined &&
269 h("div", { class: "toast-header", part: "header" }, this.header), this.message !== undefined &&
270 h("div", { class: "toast-message", part: "message", innerHTML: sanitizeDOMString(this.message) })), this.renderButtons(endButtons, 'end')))));
271 }
272 get el() { return this; }
273 static get style() { return {
274 ios: toastIosCss,
275 md: toastMdCss
276 }; }
277}, [33, "ion-toast", {
278 "overlayIndex": [2, "overlay-index"],
279 "color": [513],
280 "enterAnimation": [16],
281 "leaveAnimation": [16],
282 "cssClass": [1, "css-class"],
283 "duration": [2],
284 "header": [1],
285 "message": [1],
286 "keyboardClose": [4, "keyboard-close"],
287 "position": [1],
288 "buttons": [16],
289 "translucent": [4],
290 "animated": [4],
291 "icon": [1],
292 "htmlAttributes": [16],
293 "present": [64],
294 "dismiss": [64],
295 "onDidDismiss": [64],
296 "onWillDismiss": [64]
297 }]);
298const buttonClass = (button) => {
299 return Object.assign({ 'toast-button': true, 'toast-button-icon-only': button.icon !== undefined && button.text === undefined, [`toast-button-${button.role}`]: button.role !== undefined, 'ion-focusable': true, 'ion-activatable': true }, getClassMap(button.cssClass));
300};
301function defineCustomElement$1() {
302 if (typeof customElements === "undefined") {
303 return;
304 }
305 const components = ["ion-toast", "ion-icon", "ion-ripple-effect"];
306 components.forEach(tagName => { switch (tagName) {
307 case "ion-toast":
308 if (!customElements.get(tagName)) {
309 customElements.define(tagName, Toast);
310 }
311 break;
312 case "ion-icon":
313 if (!customElements.get(tagName)) {
314 defineCustomElement$3();
315 }
316 break;
317 case "ion-ripple-effect":
318 if (!customElements.get(tagName)) {
319 defineCustomElement$2();
320 }
321 break;
322 } });
323}
324
325const IonToast = Toast;
326const defineCustomElement = defineCustomElement$1;
327
328export { IonToast, defineCustomElement };