mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
feat(alert, toast): pass arbitrary HTML attributes to host element (#23891)
resolves #23825
This commit is contained in:
@ -50,6 +50,7 @@ ion-alert,prop,buttons,(string | AlertButton)[],[],false,false
|
||||
ion-alert,prop,cssClass,string | string[] | undefined,undefined,false,false
|
||||
ion-alert,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-alert,prop,header,string | undefined,undefined,false,false
|
||||
ion-alert,prop,htmlAttributes,AlertAttributes | undefined,undefined,false,false
|
||||
ion-alert,prop,inputs,AlertInput[],[],false,false
|
||||
ion-alert,prop,keyboardClose,boolean,true,false,false
|
||||
ion-alert,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
@ -1268,6 +1269,7 @@ ion-toast,prop,cssClass,string | string[] | undefined,undefined,false,false
|
||||
ion-toast,prop,duration,number,0,false,false
|
||||
ion-toast,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-toast,prop,header,string | undefined,undefined,false,false
|
||||
ion-toast,prop,htmlAttributes,ToastAttributes | undefined,undefined,false,false
|
||||
ion-toast,prop,keyboardClose,boolean,false,false,false
|
||||
ion-toast,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-toast,prop,message,IonicSafeString | string | undefined,undefined,false,false
|
||||
|
18
core/src/components.d.ts
vendored
18
core/src/components.d.ts
vendored
@ -7,8 +7,10 @@
|
||||
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
|
||||
import { ActionSheetButton, AlertButton, AlertInput, AnimationBuilder, AutocompleteTypes, CheckboxChangeEventDetail, Color, ComponentProps, ComponentRef, DatetimeChangeEventDetail, DatetimeOptions, DomRenderFn, FooterHeightFn, FrameworkDelegate, HeaderFn, HeaderHeightFn, InputChangeEventDetail, ItemHeightFn, ItemRenderFn, ItemReorderEventDetail, MenuChangeEventDetail, NavComponent, NavComponentWithProps, NavOptions, OverlayEventDetail, PickerButton, PickerColumn, RadioGroupChangeEventDetail, RangeChangeEventDetail, RangeValue, RefresherEventDetail, RouteID, RouterDirection, RouterEventDetail, RouterOutletOptions, RouteWrite, ScrollBaseDetail, ScrollDetail, SearchbarChangeEventDetail, SegmentButtonLayout, SegmentChangeEventDetail, SelectChangeEventDetail, SelectInterface, SelectPopoverOption, Side, SpinnerTypes, StyleEventDetail, SwipeGestureHandler, TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout, TextareaChangeEventDetail, TextFieldTypes, ToastButton, ToggleChangeEventDetail, TransitionDoneFn, TransitionInstruction, ViewController } from "./interface";
|
||||
import { IonicSafeString } from "./utils/sanitization";
|
||||
import { AlertAttributes } from "./components/alert/alert-interface";
|
||||
import { NavigationHookCallback } from "./components/route/route-interface";
|
||||
import { SelectCompareFn } from "./components/select/select-interface";
|
||||
import { ToastAttributes } from "./components/toast/toast-interface";
|
||||
export namespace Components {
|
||||
interface IonActionSheet {
|
||||
/**
|
||||
@ -106,6 +108,10 @@ export namespace Components {
|
||||
* The main title in the heading of the alert.
|
||||
*/
|
||||
"header"?: string;
|
||||
/**
|
||||
* Additional attributes to pass to the alert.
|
||||
*/
|
||||
"htmlAttributes"?: AlertAttributes;
|
||||
/**
|
||||
* Array of input to show in the alert.
|
||||
*/
|
||||
@ -2565,6 +2571,10 @@ export namespace Components {
|
||||
* Header to be shown in the toast.
|
||||
*/
|
||||
"header"?: string;
|
||||
/**
|
||||
* Additional attributes to pass to the toast.
|
||||
*/
|
||||
"htmlAttributes"?: ToastAttributes;
|
||||
/**
|
||||
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
|
||||
*/
|
||||
@ -3409,6 +3419,10 @@ declare namespace LocalJSX {
|
||||
* The main title in the heading of the alert.
|
||||
*/
|
||||
"header"?: string;
|
||||
/**
|
||||
* Additional attributes to pass to the alert.
|
||||
*/
|
||||
"htmlAttributes"?: AlertAttributes;
|
||||
/**
|
||||
* Array of input to show in the alert.
|
||||
*/
|
||||
@ -5894,6 +5908,10 @@ declare namespace LocalJSX {
|
||||
* Header to be shown in the toast.
|
||||
*/
|
||||
"header"?: string;
|
||||
/**
|
||||
* Additional attributes to pass to the toast.
|
||||
*/
|
||||
"htmlAttributes"?: ToastAttributes;
|
||||
/**
|
||||
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@ export interface AlertOptions {
|
||||
backdropDismiss?: boolean;
|
||||
translucent?: boolean;
|
||||
animated?: boolean;
|
||||
htmlAttributes?: AlertAttributes;
|
||||
|
||||
mode?: Mode;
|
||||
keyboardClose?: boolean;
|
||||
@ -22,6 +23,8 @@ export interface AlertOptions {
|
||||
leaveAnimation?: AnimationBuilder;
|
||||
}
|
||||
|
||||
export interface AlertAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
|
||||
|
||||
export interface AlertInput {
|
||||
type?: TextFieldTypes | 'checkbox' | 'radio' | 'textarea';
|
||||
name?: string;
|
||||
|
@ -8,6 +8,7 @@ import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safe
|
||||
import { IonicSafeString, sanitizeDOMString } from '../../utils/sanitization';
|
||||
import { getClassMap } from '../../utils/theme';
|
||||
|
||||
import { AlertAttributes } from './alert-interface';
|
||||
import { iosEnterAnimation } from './animations/ios.enter';
|
||||
import { iosLeaveAnimation } from './animations/ios.leave';
|
||||
import { mdEnterAnimation } from './animations/md.enter';
|
||||
@ -110,6 +111,11 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
*/
|
||||
@Prop() animated = true;
|
||||
|
||||
/**
|
||||
* Additional attributes to pass to the alert.
|
||||
*/
|
||||
@Prop() htmlAttributes?: AlertAttributes;
|
||||
|
||||
/**
|
||||
* Emitted after the alert has presented.
|
||||
*/
|
||||
@ -550,15 +556,16 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { overlayIndex, header, subHeader } = this;
|
||||
const { overlayIndex, header, subHeader, htmlAttributes } = this;
|
||||
const mode = getIonMode(this);
|
||||
const hdrId = `alert-${overlayIndex}-hdr`;
|
||||
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
|
||||
const msgId = `alert-${overlayIndex}-msg`;
|
||||
const role = htmlAttributes?.role || (this.inputs.length > 0 || this.buttons.length > 0 ? 'alertdialog' : 'alert');
|
||||
|
||||
return (
|
||||
<Host
|
||||
role="dialog"
|
||||
role={role}
|
||||
aria-modal="true"
|
||||
tabindex="-1"
|
||||
style={{
|
||||
@ -571,6 +578,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
}}
|
||||
onIonAlertWillDismiss={this.dispatchCancelHandler}
|
||||
onIonBackdropTap={this.onBackdropTap}
|
||||
{...htmlAttributes as any}
|
||||
>
|
||||
|
||||
<ion-backdrop tappable={this.backdropDismiss}/>
|
||||
|
@ -95,6 +95,7 @@ interface AlertOptions {
|
||||
backdropDismiss?: boolean;
|
||||
translucent?: boolean;
|
||||
animated?: boolean;
|
||||
htmlAttributes?: AlertAttributes;
|
||||
|
||||
mode?: Mode;
|
||||
keyboardClose?: boolean;
|
||||
@ -105,6 +106,11 @@ interface AlertOptions {
|
||||
}
|
||||
```
|
||||
|
||||
### AlertAttributes
|
||||
```typescript
|
||||
interface AlertAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
|
||||
```
|
||||
|
||||
### AlertTextareaAttributes
|
||||
```typescript
|
||||
interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
@ -1768,6 +1774,7 @@ export default defineComponent({
|
||||
| `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` |
|
||||
| `enterAnimation` | -- | Animation to use when the alert is presented. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `header` | `header` | The main title in the heading of the alert. | `string \| undefined` | `undefined` |
|
||||
| `htmlAttributes` | -- | Additional attributes to pass to the alert. | `AlertAttributes \| undefined` | `undefined` |
|
||||
| `inputs` | -- | Array of input to show in the alert. | `AlertInput[]` | `[]` |
|
||||
| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
|
||||
| `leaveAnimation` | -- | Animation to use when the alert is dismissed. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
|
@ -102,3 +102,21 @@ test(`alert:rtl: basic, radio`, async () => {
|
||||
test(`alert:rtl: basic, checkbox`, async () => {
|
||||
await testAlert(DIRECTORY, '#checkbox', true);
|
||||
});
|
||||
|
||||
// Attributes
|
||||
|
||||
test('alert: htmlAttributes', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/alert/test/basic?ionic:_testing=true' });
|
||||
|
||||
await page.click('#basic');
|
||||
await page.waitForSelector('#basic');
|
||||
|
||||
let alert = await page.find('ion-alert');
|
||||
|
||||
expect(alert).not.toBe(null);
|
||||
await alert.waitForVisible();
|
||||
|
||||
const attribute = await page.evaluate((el) => document.querySelector('ion-alert').getAttribute('data-testid'));
|
||||
|
||||
expect(attribute).toEqual('basic-alert');
|
||||
});
|
||||
|
@ -58,7 +58,10 @@
|
||||
header: 'Alert',
|
||||
subHeader: 'Subtitle',
|
||||
message: 'This is an alert message.',
|
||||
buttons: ['OK']
|
||||
buttons: ['OK'],
|
||||
htmlAttributes: {
|
||||
'data-testid': 'basic-alert'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@ interface ToastOptions {
|
||||
position?: 'top' | 'bottom' | 'middle';
|
||||
translucent?: boolean;
|
||||
animated?: boolean;
|
||||
htmlAttributes?: ToastAttributes;
|
||||
|
||||
color?: Color;
|
||||
mode?: Mode;
|
||||
@ -48,6 +49,11 @@ interface ToastOptions {
|
||||
}
|
||||
```
|
||||
|
||||
### ToastAttributes
|
||||
```typescript
|
||||
interface ToastAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
|
||||
```
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
@ -405,6 +411,7 @@ export default defineComponent({
|
||||
| `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. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `header` | `header` | Header to be shown in the toast. | `string \| undefined` | `undefined` |
|
||||
| `htmlAttributes` | -- | Additional attributes to pass to the toast. | `ToastAttributes \| 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. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` |
|
||||
| `message` | `message` | Message to be shown in the toast. | `IonicSafeString \| string \| undefined` | `undefined` |
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
import { testToast } from '../test.utils';
|
||||
|
||||
const DIRECTORY = 'basic';
|
||||
@ -101,3 +102,21 @@ test('toast:rtl: start end position', async () => {
|
||||
test('toast:rtl: html', async () => {
|
||||
await testToast(DIRECTORY, '#toast-html', true);
|
||||
});
|
||||
|
||||
// Attributes
|
||||
|
||||
test('toast: htmlAttributes', async () => {
|
||||
const page = await newE2EPage({ url: '/src/components/toast/test/basic?ionic:_testing=true' });
|
||||
|
||||
await page.click('#show-bottom-toast');
|
||||
await page.waitForSelector('#show-bottom-toast');
|
||||
|
||||
let toast = await page.find('ion-toast');
|
||||
|
||||
expect(toast).not.toBe(null);
|
||||
await toast.waitForVisible();
|
||||
|
||||
const attribute = await page.evaluate((el) => document.querySelector('ion-toast').getAttribute('data-testid'));
|
||||
|
||||
expect(attribute).toEqual('basic-toast');
|
||||
});
|
||||
|
@ -23,7 +23,7 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding" id="content">
|
||||
<ion-button expand="block" id="show-bottom-toast" onclick="openToast({ message: 'Hellooo', position: 'bottom', duration: 2000 })">
|
||||
<ion-button expand="block" id="show-bottom-toast" onclick="openToast({ message: 'Hellooo', position: 'bottom', duration: 2000, htmlAttributes: { 'data-testid': 'basic-toast' } })">
|
||||
Position Bottom
|
||||
</ion-button>
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { JSXBase } from '@stencil/core/internal';
|
||||
|
||||
import { AnimationBuilder, Color, Mode } from '../../interface';
|
||||
import { IonicSafeString } from '../../utils/sanitization';
|
||||
|
||||
@ -10,6 +12,7 @@ export interface ToastOptions {
|
||||
position?: 'top' | 'bottom' | 'middle';
|
||||
translucent?: boolean;
|
||||
animated?: boolean;
|
||||
htmlAttributes?: ToastAttributes;
|
||||
|
||||
color?: Color;
|
||||
mode?: Mode;
|
||||
@ -20,6 +23,8 @@ export interface ToastOptions {
|
||||
leaveAnimation?: AnimationBuilder;
|
||||
}
|
||||
|
||||
export interface ToastAttributes extends JSXBase.HTMLAttributes<HTMLElement> {}
|
||||
|
||||
export interface ToastButton {
|
||||
text?: string;
|
||||
icon?: string;
|
||||
|
@ -10,6 +10,7 @@ import { iosEnterAnimation } from './animations/ios.enter';
|
||||
import { iosLeaveAnimation } from './animations/ios.leave';
|
||||
import { mdEnterAnimation } from './animations/md.enter';
|
||||
import { mdLeaveAnimation } from './animations/md.leave';
|
||||
import { ToastAttributes } from './toast-interface';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
@ -106,6 +107,11 @@ export class Toast implements ComponentInterface, OverlayInterface {
|
||||
*/
|
||||
@Prop() animated = true;
|
||||
|
||||
/**
|
||||
* Additional attributes to pass to the toast.
|
||||
*/
|
||||
@Prop() htmlAttributes?: ToastAttributes;
|
||||
|
||||
/**
|
||||
* Emitted after the toast has presented.
|
||||
*/
|
||||
@ -263,6 +269,7 @@ export class Toast implements ComponentInterface, OverlayInterface {
|
||||
'toast-wrapper': true,
|
||||
[`toast-${this.position}`]: true
|
||||
};
|
||||
const role = this.htmlAttributes?.role || (allButtons.length > 0 ? 'dialog' : 'status');
|
||||
|
||||
return (
|
||||
<Host
|
||||
@ -276,6 +283,8 @@ export class Toast implements ComponentInterface, OverlayInterface {
|
||||
})}
|
||||
tabindex="-1"
|
||||
onIonToastWillDismiss={this.dispatchCancelHandler}
|
||||
role={role}
|
||||
{...this.htmlAttributes as any}
|
||||
>
|
||||
<div class={wrapperClass}>
|
||||
<div class="toast-container" part="container">
|
||||
|
@ -15,7 +15,7 @@ import { defineOverlayContainer } from '../vue-component-lib/overlays';
|
||||
|
||||
export const IonActionSheet = /*@__PURE__*/defineOverlayContainer<JSX.IonActionSheet>('ion-action-sheet', ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'mode', 'subHeader', 'translucent'], actionSheetController);
|
||||
|
||||
export const IonAlert = /*@__PURE__*/defineOverlayContainer<JSX.IonAlert>('ion-alert', ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController);
|
||||
export const IonAlert = /*@__PURE__*/defineOverlayContainer<JSX.IonAlert>('ion-alert', ['animated', 'backdropDismiss', 'buttons', 'cssClass', 'enterAnimation', 'header', 'htmlAttributes', 'inputs', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'subHeader', 'translucent'], alertController);
|
||||
|
||||
export const IonLoading = /*@__PURE__*/defineOverlayContainer<JSX.IonLoading>('ion-loading', ['animated', 'backdropDismiss', 'cssClass', 'duration', 'enterAnimation', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'showBackdrop', 'spinner', 'translucent'], loadingController);
|
||||
|
||||
@ -25,5 +25,5 @@ export const IonPicker = /*@__PURE__*/defineOverlayContainer<JSX.IonPicker>('ion
|
||||
|
||||
export const IonPopover = /*@__PURE__*/defineOverlayContainer<JSX.IonPopover>('ion-popover', ['animated', 'backdropDismiss', 'component', 'componentProps', 'cssClass', 'enterAnimation', 'event', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'translucent'], popoverController);
|
||||
|
||||
export const IonToast = /*@__PURE__*/defineOverlayContainer<JSX.IonToast>('ion-toast', ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController);
|
||||
export const IonToast = /*@__PURE__*/defineOverlayContainer<JSX.IonToast>('ion-toast', ['animated', 'buttons', 'color', 'cssClass', 'duration', 'enterAnimation', 'header', 'htmlAttributes', 'keyboardClose', 'leaveAnimation', 'message', 'mode', 'position', 'translucent'], toastController);
|
||||
|
||||
|
Reference in New Issue
Block a user