diff --git a/core/api.txt b/core/api.txt index 55781e9204..f56840ae43 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1135,11 +1135,13 @@ ion-toast-controller,method,getTop,getTop() => Promise Promise) | undefined,undefined,false,false +ion-toast,prop,header,string | undefined,undefined,false,false ion-toast,prop,keyboardClose,boolean,false,false,false ion-toast,prop,leaveAnimation,((Animation: Animation, baseEl: any, opts?: any) => Promise) | undefined,undefined,false,false ion-toast,prop,message,string | undefined,undefined,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index db0d7904c1..89660ce0bb 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -68,6 +68,7 @@ import { TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, + ToastButton, ToastOptions, ToggleChangeEventDetail, TransitionDoneFn, @@ -4757,6 +4758,10 @@ export namespace Components { */ 'animated': boolean; /** + * An array of buttons for the toast. + */ + 'buttons'?: (ToastButton | string)[]; + /** * Text to display in the close button. */ 'closeButtonText'?: string; @@ -4781,6 +4786,10 @@ export namespace Components { */ 'enterAnimation'?: AnimationBuilder; /** + * Header to be shown in the toast. + */ + 'header'?: string; + /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ 'keyboardClose': boolean; @@ -4828,6 +4837,10 @@ export namespace Components { */ 'animated'?: boolean; /** + * An array of buttons for the toast. + */ + 'buttons'?: (ToastButton | string)[]; + /** * Text to display in the close button. */ 'closeButtonText'?: string; @@ -4848,6 +4861,10 @@ export namespace Components { */ 'enterAnimation'?: AnimationBuilder; /** + * Header to be shown in the toast. + */ + 'header'?: string; + /** * If `true`, the keyboard will be automatically dismissed when the overlay is presented. */ 'keyboardClose'?: boolean; diff --git a/core/src/components/toast/readme.md b/core/src/components/toast/readme.md index 091a3f7c0e..9b4fb44d0b 100644 --- a/core/src/components/toast/readme.md +++ b/core/src/components/toast/readme.md @@ -45,10 +45,25 @@ export class ToastExample { async presentToastWithOptions() { const toast = await this.toastController.create({ + header: 'Toast header', message: 'Click to Close', - showCloseButton: true, position: 'top', - closeButtonText: 'Done' + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + } + ] }); toast.present(); } @@ -76,11 +91,27 @@ async function presentToastWithOptions() { await toastController.componentOnReady(); const toast = await toastController.create({ + header: 'Toast header', message: 'Click to Close', - showCloseButton: true, position: 'top', - closeButtonText: 'Done' + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + } + ] }); + return await toast.present(); } ``` @@ -122,9 +153,21 @@ export class Toast extends Component { isOpen={this.state.showToast2} onDidDismiss={() => this.setState(() => ({ showToast2: false }))} message='Click to Close' - showCloseButton={true} position='top' - closeButtonText='Done' + buttons={[{ + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + }]} > ); @@ -140,11 +183,13 @@ export class Toast extends Component { | Property | Attribute | Description | Type | Default | | ----------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | | `animated` | `animated` | If `true`, the toast will animate. | `boolean` | `true` | +| `buttons` | -- | An array of buttons for the toast. | `(string \| ToastButton)[] \| undefined` | `undefined` | | `closeButtonText` | `close-button-text` | Text to display in the close button. | `string \| undefined` | `undefined` | | `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | | `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` | | `duration` | `duration` | How many milliseconds to wait before hiding the toast. By default, it will show until `dismiss()` is called. | `number` | `0` | | `enterAnimation` | -- | Animation to use when the toast is presented. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` | +| `header` | `header` | Header to be shown in the toast. | `string \| undefined` | `undefined` | | `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `false` | | `leaveAnimation` | -- | Animation to use when the toast is dismissed. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` | | `message` | `message` | Message to be shown in the toast. | `string \| undefined` | `undefined` | diff --git a/core/src/components/toast/test/basic/e2e.ts b/core/src/components/toast/test/basic/e2e.ts index 6ae84ab82a..a17ea53204 100644 --- a/core/src/components/toast/test/basic/e2e.ts +++ b/core/src/components/toast/test/basic/e2e.ts @@ -26,6 +26,10 @@ test('toast: custom close text', async () => { await testToast(DIRECTORY, '#custom-close-text-toast'); }); +test('toast: custom buttons', async () => { + await testToast(DIRECTORY, '#custom-action-buttons-toast'); +}); + test('toast: translucent', async () => { await testToast(DIRECTORY, '#translucent-toast'); }); @@ -66,6 +70,10 @@ test('toast:rtl: custom close text', async () => { await testToast(DIRECTORY, '#custom-close-text-toast', true); }); +test('toast:rtl: custom buttons', async () => { + await testToast(DIRECTORY, '#custom-action-buttons-toast'); +}); + test('toast:rtl: translucent', async () => { await testToast(DIRECTORY, '#translucent-toast', true); }); diff --git a/core/src/components/toast/test/basic/index.html b/core/src/components/toast/test/basic/index.html index 42f1d4b7ce..c4698c0a6f 100644 --- a/core/src/components/toast/test/basic/index.html +++ b/core/src/components/toast/test/basic/index.html @@ -13,54 +13,92 @@ - - - Toast - Basic - - + + + Toast - Basic + + - - Show Toast Bottom - Show Toast Top - Show Toast Middle - Show Toast with long message - Show Toast with Close Button - Show Toast with Custom Close Button Text - Show Translucent Toast - Show Color Toast - Show Toast with Custom Class + + + Position Bottom + - + + Position Top + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Position Middle + + + + Header Toast + + + + Header + Action Toast + + + + Long Message + + + + Close Button + + + + Custom Close Button + + + + Custom Buttons + + + + Translucent Toast + + + + Color Toast + + + + Custom Class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/core/src/components/toast/test/buttons/e2e.ts b/core/src/components/toast/test/buttons/e2e.ts new file mode 100644 index 0000000000..af658bf40e --- /dev/null +++ b/core/src/components/toast/test/buttons/e2e.ts @@ -0,0 +1,47 @@ +import { testToast } from '../test.utils'; + +const DIRECTORY = 'buttons'; + +test('toast: close property', async () => { + await testToast(DIRECTORY, '#closeProp'); +}); + +test('toast: close array', async () => { + await testToast(DIRECTORY, '#closeArray'); +}); + +test('toast: two buttons', async () => { + await testToast(DIRECTORY, '#twoButtons'); +}); + +test('toast: multiple buttons', async () => { + await testToast(DIRECTORY, '#multipleButtons'); +}); + +test('toast: long button', async () => { + await testToast(DIRECTORY, '#longButton'); +}); + +/** + * RTL Tests + */ + +test('toast:rtl: close property', async () => { + await testToast(DIRECTORY, '#closeProp', true); +}); + +test('toast:rtl: close array', async () => { + await testToast(DIRECTORY, '#closeArray', true); +}); + +test('toast:rtl: two buttons', async () => { + await testToast(DIRECTORY, '#twoButtons', true); +}); + +test('toast:rtl: multiple buttons', async () => { + await testToast(DIRECTORY, '#multipleButtons', true); +}); + +test('toast:rtl: long button', async () => { + await testToast(DIRECTORY, '#longButton', true); +}); diff --git a/core/src/components/toast/test/buttons/index.html b/core/src/components/toast/test/buttons/index.html new file mode 100644 index 0000000000..3973f100ad --- /dev/null +++ b/core/src/components/toast/test/buttons/index.html @@ -0,0 +1,159 @@ + + + + + + Toast - Buttons + + + + + + + + + + + + Toast - Buttons + + + + + + + Close Button Property + + + + + Close Button Array + + + + Two Buttons + + + + Multiple Buttons + + + + Really Long Button + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/components/toast/test/preview/index.html b/core/src/components/toast/test/preview/index.html deleted file mode 100644 index d4aaef7dc6..0000000000 --- a/core/src/components/toast/test/preview/index.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - Toast - - - - - - - - - - - - Toast - - - - - Show Toast Bottom - Show Toast Top - Show Toast Middle - Show Toast with long message - Show Toast with Close Button - Show Toast with Custom Close Button Text - Show Translucent Toast - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/components/toast/toast-interface.ts b/core/src/components/toast/toast-interface.ts index 2de3540f7f..a846938435 100644 --- a/core/src/components/toast/toast-interface.ts +++ b/core/src/components/toast/toast-interface.ts @@ -1,6 +1,7 @@ import { AnimationBuilder, Color, Mode } from '../../interface'; export interface ToastOptions { + header?: string; message?: string; cssClass?: string | string[]; duration?: number; @@ -18,3 +19,12 @@ export interface ToastOptions { enterAnimation?: AnimationBuilder; leaveAnimation?: AnimationBuilder; } + +export interface ToastButton { + text?: string; + icon?: string; + side?: 'start' | 'end'; + role?: 'cancel' | string; + cssClass?: string | string[]; + handler?: () => boolean | void | Promise; +} diff --git a/core/src/components/toast/toast.ios.scss b/core/src/components/toast/toast.ios.scss index 5ec1c201e7..a7e90dd251 100644 --- a/core/src/components/toast/toast.ios.scss +++ b/core/src/components/toast/toast.ios.scss @@ -11,7 +11,7 @@ --color: #{$toast-ios-title-color}; --max-width: #{$toast-max-width}; - font-size: $toast-ios-title-font-size; + font-size: $toast-ios-content-font-size; } .toast-wrapper { @@ -45,10 +45,48 @@ bottom: 0; } -.toast-message { - @include padding($toast-ios-title-padding-top, $toast-ios-title-padding-end, $toast-ios-title-padding-bottom, $toast-ios-title-padding-start); +.toast-content { + @include padding($toast-ios-content-padding-top, $toast-ios-content-padding-end, $toast-ios-content-padding-bottom, $toast-ios-content-padding-start); } +.toast-header { + margin-bottom: $toast-ios-header-margin-bottom; + + font-weight: $toast-ios-header-font-weight; +} + +// iOS Toast Button +// -------------------------------------------------- + .toast-button { - font-size: $toast-button-font-size; + @include padding($toast-ios-button-padding-top, $toast-ios-button-padding-end, $toast-ios-button-padding-bottom, $toast-ios-button-padding-start); + + height: $toast-ios-button-min-height; + + transition: background-color, opacity 100ms linear; + + border: 0; + + background-color: $toast-ios-button-background-color; + color: $toast-ios-button-text-color; + + font-family: var(--ion-font-family); + font-size: $toast-ios-button-font-size; + font-weight: $toast-ios-button-font-weight; + + overflow: hidden; +} + +.toast-button.activated { + opacity: $toast-ios-button-opacity-activated; +} + + +// iOS Toast Button: Hover +// -------------------------------------------------- + +@media (any-hover: hover) { + .toast-button:hover { + opacity: .6; + } } \ No newline at end of file diff --git a/core/src/components/toast/toast.ios.vars.scss b/core/src/components/toast/toast.ios.vars.scss index 14a28cb396..a8762f2e78 100644 --- a/core/src/components/toast/toast.ios.vars.scss +++ b/core/src/components/toast/toast.ios.vars.scss @@ -19,22 +19,58 @@ $toast-ios-border-radius: 14px !default; $toast-ios-title-color: $text-color-step-150 !default; /// @prop - Font size of the toast title -$toast-ios-title-font-size: 14px !default; +$toast-ios-header-font-weight: 500 !default; -/// @prop - Padding top of the toast title -$toast-ios-title-padding-top: 15px !default; +/// @prop - Spacing between the header and the message +$toast-ios-header-margin-bottom: 2px !default; -/// @prop - Padding end of the toast title -$toast-ios-title-padding-end: $toast-ios-title-padding-top !default; +/// @prop - Font size of the toast title +$toast-ios-content-font-size: 14px !default; -/// @prop - Padding bottom of the toast title -$toast-ios-title-padding-bottom: $toast-ios-title-padding-top !default; +/// @prop - Padding top of the toast content +$toast-ios-content-padding-top: 15px !default; -/// @prop - Padding start of the toast title -$toast-ios-title-padding-start: $toast-ios-title-padding-end !default; +/// @prop - Padding end of the toast content +$toast-ios-content-padding-end: $toast-ios-content-padding-top !default; + +/// @prop - Padding bottom of the toast content +$toast-ios-content-padding-bottom: $toast-ios-content-padding-top !default; + +/// @prop - Padding start of the toast content +$toast-ios-content-padding-start: $toast-ios-content-padding-end !default; /// @prop - Color of the toast button $toast-ios-button-color: $text-color-step-400 !default; /// @prop - Filter of the translucent toast $toast-ios-translucent-filter: saturate(180%) blur(20px) !default; + +/// @prop - Minimum height of the toast button +$toast-ios-button-min-height: 44px !default; + +/// @prop - Padding top of the toast button +$toast-ios-button-padding-top: 10px !default; + +/// @prop - Padding end of the toast button +$toast-ios-button-padding-end: 15px !default; + +/// @prop - Padding bottom of the toast button +$toast-ios-button-padding-bottom: $toast-ios-button-padding-top !default; + +/// @prop - Padding start of the toast button +$toast-ios-button-padding-start: 15px !default; + +/// @prop - Font size of the toast button +$toast-ios-button-font-size: 17px !default; + +/// @prop - Font size of the toast button +$toast-ios-button-font-weight: 500 !default; + +/// @prop - Color of the text in the toast button +$toast-ios-button-text-color: ion-color(primary, base) !default; + +/// @prop - Background color alpha of the toast activated button +$toast-ios-button-opacity-activated: .4 !default; + +/// @prop - Background color of the toast button +$toast-ios-button-background-color: transparent !default; diff --git a/core/src/components/toast/toast.md.scss b/core/src/components/toast/toast.md.scss index 489d25ddb6..39693da381 100644 --- a/core/src/components/toast/toast.md.scss +++ b/core/src/components/toast/toast.md.scss @@ -27,12 +27,77 @@ z-index: $z-index-overlay-wrapper; } -.toast-message { - @include padding($toast-md-message-padding-top, $toast-md-message-padding-end, $toast-md-message-padding-bottom, $toast-md-message-padding-start); +.toast-content { + @include padding($toast-md-content-padding-top, $toast-md-content-padding-end, $toast-md-content-padding-bottom, $toast-md-content-padding-start); +} +.toast-header { + margin-bottom: $toast-md-header-margin-bottom; + + font-weight: $toast-md-header-font-weight; + + line-height: $toast-md-header-line-height; +} + +.toast-message { line-height: $toast-md-message-line-height; } -.toast-button { - --margin-end: 0; + +// Material Design Toast Button +// -------------------------------------------------- + + +.toast-button-group-start { + @include margin(null, null, null, 8px); +} + +.toast-button-group-end { + @include margin(null, 8px, null, null); +} + +.toast-button { + @include padding($toast-md-button-padding-top, $toast-md-button-padding-end, $toast-md-button-padding-bottom, $toast-md-button-padding-start); + + // necessary for ripple to work properly + position: relative; + + background-color: $toast-md-button-background-color; + color: $toast-md-button-text-color; + + font-family: var(--ion-font-family); + font-size: $toast-md-button-font-size; + font-weight: $toast-md-button-font-weight; + + letter-spacing: $toast-md-button-letter-spacing; + + text-transform: $toast-md-button-text-transform; + + overflow: hidden; +} + +.toast-button-cancel { + color: $toast-md-button-cancel-text-color; +} + +.toast-button-icon-only { + @include border-radius($toast-md-button-icon-only-border-radius); + @include padding($toast-md-button-icon-only-padding); + + width: $toast-md-button-icon-only-width; + height: $toast-md-button-icon-only-height; +} + + +// Material Design Toast Button: Hover +// -------------------------------------------------- + +@media (any-hover: hover) { + .toast-button:hover { + background-color: $toast-md-button-background-color-hover; + } + + .toast-button-cancel:hover { + background-color: $toast-md-button-cancel-background-color-hover; + } } diff --git a/core/src/components/toast/toast.md.vars.scss b/core/src/components/toast/toast.md.vars.scss index f451852e55..0bdea72ff0 100644 --- a/core/src/components/toast/toast.md.vars.scss +++ b/core/src/components/toast/toast.md.vars.scss @@ -18,17 +18,80 @@ $toast-md-color: $background-color-step-50 !de /// @prop - Border radius of the toast wrapper $toast-md-border-radius: 4px !default; +/// @prop - Font size of the toast message +$toast-md-header-line-height: 20px !default; + +/// @prop - Font size of the toast message +$toast-md-header-font-weight: 500 !default; + +/// @prop - Spacing between the header and the message +$toast-md-header-margin-bottom: 2px !default; + /// @prop - Font size of the toast message $toast-md-message-line-height: 20px !default; /// @prop - Padding top of the toast message -$toast-md-message-padding-top: 14px !default; +$toast-md-content-padding-top: 14px !default; -/// @prop - Padding end of the toast message -$toast-md-message-padding-end: 16px !default; +/// @prop - Padding end of the toast content +$toast-md-content-padding-end: 16px !default; -/// @prop - Padding bottom of the toast message -$toast-md-message-padding-bottom: $toast-md-message-padding-top !default; +/// @prop - Padding bottom of the toast content +$toast-md-content-padding-bottom: $toast-md-content-padding-top !default; -/// @prop - Padding start of the toast message -$toast-md-message-padding-start: $toast-md-message-padding-end !default; +/// @prop - Padding start of the toast content +$toast-md-content-padding-start: $toast-md-content-padding-end !default; + +/// @prop - Padding top of the toast button +$toast-md-button-padding-top: 10px !default; + +/// @prop - Padding end of the toast button +$toast-md-button-padding-end: 15px !default; + +/// @prop - Padding bottom of the toast button +$toast-md-button-padding-bottom: $toast-md-button-padding-top !default; + +/// @prop - Padding start of the toast button +$toast-md-button-padding-start: 15px !default; + +/// @prop - Font size of the toast button +$toast-md-button-font-size: 14px !default; + +/// @prop - Font weight of the toast button +$toast-md-button-font-weight: 500 !default; + +/// @prop - Letter spacing of the toast button +$toast-md-button-letter-spacing: 0.84px !default; + +/// @prop - Text color of the toast button +$toast-md-button-text-color: ion-color(primary, base) !default; + +/// @prop - Background color of the toast button +$toast-md-button-background-color: transparent !default; + +/// @prop - Text transform of the toast button +$toast-md-button-text-transform: uppercase !default; + +/// @prop - Opacity of the toast button background on hover +$toast-md-button-opacity-hover: 0.08 !default; + +/// @prop - Background color of the toast button on hover +$toast-md-button-background-color-hover: ion-color(primary, base, $toast-md-button-opacity-hover) !default; + +/// @prop - Text color of the cancel toast button +$toast-md-button-cancel-text-color: $background-color-step-100 !default; + +/// @prop - Background color of the cancel toast button on hover +$toast-md-button-cancel-background-color-hover: rgba($background-color-rgb, $toast-md-button-opacity-hover) !default; + +/// @prop - Padding of the icon only toast button +$toast-md-button-icon-only-padding: 9px !default; + +/// @prop - Width of the icon only toast button +$toast-md-button-icon-only-width: 36px !default; + +/// @prop - Height of the icon only toast button +$toast-md-button-icon-only-height: $toast-md-button-icon-only-width !default; + +/// @prop - Border radius of the icon only toast button +$toast-md-button-icon-only-border-radius: 50% !default; diff --git a/core/src/components/toast/toast.scss b/core/src/components/toast/toast.scss index 025be08a92..034cfc92ac 100644 --- a/core/src/components/toast/toast.scss +++ b/core/src/components/toast/toast.scss @@ -95,12 +95,51 @@ contain: content; } -.toast-button { - color: var(--button-color); +.toast-content { + display: flex; + + flex: 1; + flex-direction: column; + justify-content: center; } + .toast-message { flex: 1; white-space: pre-wrap; } + +.toast-button-group { + display: flex; +} + +.toast-button { + border: 0; + + outline: none; + + color: var(--button-color); + + z-index: 0; +} + +.toast-icon { + font-size: 1.4em; +} + +.toast-button-inner { + display: flex; + + align-items: center; +} + + +// Toast Button: Hover +// -------------------------------------------------- + +@media (any-hover: hover) { + .toast-button:hover { + cursor: pointer; + } +} \ No newline at end of file diff --git a/core/src/components/toast/toast.tsx b/core/src/components/toast/toast.tsx index a1e27ce363..1d3a6ad682 100644 --- a/core/src/components/toast/toast.tsx +++ b/core/src/components/toast/toast.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop } from '@stencil/core'; -import { Animation, AnimationBuilder, Color, Config, Mode, OverlayEventDetail, OverlayInterface } from '../../interface'; -import { dismiss, eventMethod, present } from '../../utils/overlays'; +import { Animation, AnimationBuilder, Color, Config, CssClassMap, Mode, OverlayEventDetail, OverlayInterface, ToastButton } from '../../interface'; +import { dismiss, eventMethod, isCancel, present } from '../../utils/overlays'; import { createColorClasses, getClassMap } from '../../utils/theme'; import { iosEnterAnimation } from './animations/ios.enter'; @@ -56,11 +56,6 @@ export class Toast implements ComponentInterface, OverlayInterface { */ @Prop() leaveAnimation?: AnimationBuilder; - /** - * Text to display in the close button. - */ - @Prop() closeButtonText?: string; - /** * Additional classes to apply for custom CSS. If multiple classes are * provided they should be separated by spaces. @@ -73,6 +68,11 @@ export class Toast implements ComponentInterface, OverlayInterface { */ @Prop() duration = 0; + /** + * Header to be shown in the toast. + */ + @Prop() header?: string; + /** * Message to be shown in the toast. */ @@ -93,6 +93,16 @@ export class Toast implements ComponentInterface, OverlayInterface { */ @Prop() showCloseButton = false; + /** + * Text to display in the close button. + */ + @Prop() closeButtonText?: string; + + /** + * An array of buttons for the toast. + */ + @Prop() buttons?: (ToastButton | string)[]; + /** * If `true`, the toast will be translucent. */ @@ -162,6 +172,54 @@ export class Toast implements ComponentInterface, OverlayInterface { return eventMethod(this.el, 'ionToastWillDismiss'); } + private getButtons(): ToastButton[] { + const buttons = this.buttons + ? this.buttons.map(b => { + return (typeof b === 'string') + ? { text: b } + : b; + }) + : []; + + if (this.showCloseButton) { + buttons.push({ + text: this.closeButtonText || 'Close', + handler: () => this.dismiss(undefined, 'cancel') + }); + } + + return buttons; + } + + private async buttonClick(button: ToastButton) { + const role = button.role; + if (isCancel(role)) { + return this.dismiss(undefined, role); + } + const shouldDismiss = await this.callButtonHandler(button); + if (shouldDismiss) { + return this.dismiss(undefined, button.role); + } + return Promise.resolve(); + } + + private async callButtonHandler(button: ToastButton | undefined) { + if (button && button.handler) { + // a handler has been provided, execute it + // pass the handler the values from the inputs + try { + const rtn = await button.handler(); + if (rtn === false) { + // if the return value of the handler is false then do not dismiss + return false; + } + } catch (e) { + console.error(e); + } + } + return true; + } + hostData() { return { style: { @@ -175,24 +233,73 @@ export class Toast implements ComponentInterface, OverlayInterface { }; } + renderButtons(buttons: ToastButton[], side: 'start' | 'end') { + if (buttons.length === 0) { + return; + } + + const buttonGroupsClasses = { + 'toast-button-group': true, + [`toast-button-group-${side}`]: true + }; + return ( +
+ {buttons.map(b => + + )} +
+ ); + } + render() { + const allButtons = this.getButtons(); + const startButtons = allButtons.filter(b => b.side === 'start'); + const endButtons = allButtons.filter(b => b.side !== 'start'); + const wrapperClass = { 'toast-wrapper': true, [`toast-${this.position}`]: true }; + return (
- {this.message !== undefined && -
{this.message}
- } - {this.showCloseButton && - this.dismiss(undefined, 'cancel')}> - {this.closeButtonText || 'Close'} - - } + {this.renderButtons(startButtons, 'start')} + +
+ {this.header !== undefined && +
{this.header}
+ } + {this.message !== undefined && +
{this.message}
+ } +
+ + {this.renderButtons(endButtons, 'end')}
); } } + +function buttonClass(button: ToastButton): CssClassMap { + return { + '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) + }; +} diff --git a/core/src/components/toast/usage/angular.md b/core/src/components/toast/usage/angular.md index d572bf4eab..c5b47bb01e 100644 --- a/core/src/components/toast/usage/angular.md +++ b/core/src/components/toast/usage/angular.md @@ -21,10 +21,25 @@ export class ToastExample { async presentToastWithOptions() { const toast = await this.toastController.create({ + header: 'Toast header', message: 'Click to Close', - showCloseButton: true, position: 'top', - closeButtonText: 'Done' + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + } + ] }); toast.present(); } diff --git a/core/src/components/toast/usage/javascript.md b/core/src/components/toast/usage/javascript.md index c293edc537..9422932cba 100644 --- a/core/src/components/toast/usage/javascript.md +++ b/core/src/components/toast/usage/javascript.md @@ -15,11 +15,27 @@ async function presentToastWithOptions() { await toastController.componentOnReady(); const toast = await toastController.create({ + header: 'Toast header', message: 'Click to Close', - showCloseButton: true, position: 'top', - closeButtonText: 'Done' + buttons: [ + { + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + } + ] }); + return await toast.present(); } ``` diff --git a/core/src/components/toast/usage/react.md b/core/src/components/toast/usage/react.md index eced288429..0e57fc51c7 100644 --- a/core/src/components/toast/usage/react.md +++ b/core/src/components/toast/usage/react.md @@ -32,9 +32,21 @@ export class Toast extends Component { isOpen={this.state.showToast2} onDidDismiss={() => this.setState(() => ({ showToast2: false }))} message='Click to Close' - showCloseButton={true} position='top' - closeButtonText='Done' + buttons={[{ + side: 'start', + icon: 'star', + text: 'Favorite', + handler: () => { + console.log('Favorite clicked'); + } + }, { + text: 'Done', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + }]} > );