feat(select): pass cancelText property to modal interface (#30282)
Co-authored-by: Nicolas Naso <nnaso@eiwa.ag> Co-authored-by: Brandy Smith <brandyscarney@users.noreply.github.com> Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
@@ -1767,6 +1767,7 @@ ion-select,part,supporting-text
|
||||
ion-select,part,text
|
||||
|
||||
ion-select-modal,scoped
|
||||
ion-select-modal,prop,cancelText,string,'Close',false,false
|
||||
ion-select-modal,prop,header,string | undefined,undefined,false,false
|
||||
ion-select-modal,prop,multiple,boolean | undefined,undefined,false,false
|
||||
ion-select-modal,prop,options,SelectModalOption[],[],false,false
|
||||
|
||||
10
core/src/components.d.ts
vendored
@@ -3223,6 +3223,11 @@ export namespace Components {
|
||||
"value"?: any | null;
|
||||
}
|
||||
interface IonSelectModal {
|
||||
/**
|
||||
* The text to display on the cancel button.
|
||||
* @default 'Close'
|
||||
*/
|
||||
"cancelText": string;
|
||||
"header"?: string;
|
||||
"multiple"?: boolean;
|
||||
/**
|
||||
@@ -8548,6 +8553,11 @@ declare namespace LocalJSX {
|
||||
"value"?: any | null;
|
||||
}
|
||||
interface IonSelectModal {
|
||||
/**
|
||||
* The text to display on the cancel button.
|
||||
* @default 'Close'
|
||||
*/
|
||||
"cancelText"?: string;
|
||||
"header"?: string;
|
||||
"multiple"?: boolean;
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,11 @@ export class SelectModal implements ComponentInterface {
|
||||
|
||||
@Prop() header?: string;
|
||||
|
||||
/**
|
||||
* The text to display on the cancel button.
|
||||
*/
|
||||
@Prop() cancelText = 'Close';
|
||||
|
||||
@Prop() multiple?: boolean;
|
||||
|
||||
@Prop() options: SelectModalOption[] = [];
|
||||
@@ -149,7 +154,7 @@ export class SelectModal implements ComponentInterface {
|
||||
{this.header !== undefined && <ion-title>{this.header}</ion-title>}
|
||||
|
||||
<ion-buttons slot="end">
|
||||
<ion-button onClick={() => this.closeModal()}>Close</ion-button>
|
||||
<ion-button onClick={() => this.closeModal()}>{this.cancelText}</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
40
core/src/components/select-modal/test/custom/index.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Select - Custom</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Select Modal - Custom</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-modal is-open="true">
|
||||
<ion-select-modal multiple="false" cancel-text="Close me"></ion-select-modal>
|
||||
</ion-modal>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
const selectModal = document.querySelector('ion-select-modal');
|
||||
selectModal.options = [
|
||||
{ value: 'apple', text: 'Apple', disabled: false, checked: true },
|
||||
{ value: 'banana', text: 'Banana', disabled: false, checked: false },
|
||||
];
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
import type { SelectModalOption } from '../../select-modal-interface';
|
||||
import { SelectModalPage } from '../fixtures';
|
||||
|
||||
const options: SelectModalOption[] = [
|
||||
{ value: 'apple', text: 'Apple', disabled: false, checked: false },
|
||||
{ value: 'banana', text: 'Banana', disabled: false, checked: false },
|
||||
];
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('select-modal: custom'), () => {
|
||||
let selectModalPage: SelectModalPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
selectModalPage = new SelectModalPage(page);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
test('should render custom cancel text when prop is provided', async ({ page: _page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/30295',
|
||||
});
|
||||
|
||||
await selectModalPage.setup(config, options, false);
|
||||
|
||||
const cancelButton = selectModalPage.selectModal.locator('ion-button');
|
||||
|
||||
// Verify the default text on the cancel button
|
||||
await expect(cancelButton).toHaveText('Close');
|
||||
|
||||
await selectModalPage.selectModal.evaluate((selectModal: HTMLIonSelectModalElement) => {
|
||||
selectModal.cancelText = 'Close me';
|
||||
});
|
||||
|
||||
// Verify the cancel button text has been updated
|
||||
await expect(cancelButton).toHaveText('Close me');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -795,6 +795,7 @@ export class Select implements ComponentInterface {
|
||||
component: 'ion-select-modal',
|
||||
componentProps: {
|
||||
header: interfaceOptions.header,
|
||||
cancelText: this.cancelText,
|
||||
multiple,
|
||||
value,
|
||||
options: this.createOverlaySelectOptions(this.childOpts, value),
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -72,5 +72,91 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
const wrapper = page.locator('.wrapper');
|
||||
await expect(wrapper).toHaveScreenshot(screenshot(`select-custom-parts-diff`));
|
||||
});
|
||||
|
||||
test('should render custom cancel text when prop is provided with alert interface', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-select label="Fruit" interface="alert" value="bananas" cancel-text="Close me">
|
||||
<ion-select-option value="apples">Apples</ion-select-option>
|
||||
<ion-select-option value="bananas">Bananas</ion-select-option>
|
||||
<ion-select-option value="oranges">Oranges</ion-select-option>
|
||||
</ion-select>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const select = page.locator('ion-select');
|
||||
const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
|
||||
|
||||
await select.click();
|
||||
await ionAlertDidPresent.next();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const alert = page.locator('ion-alert');
|
||||
const cancelButton = alert.locator('.alert-button-role-cancel');
|
||||
|
||||
// Verify the cancel button text
|
||||
await expect(cancelButton).toHaveText('Close me');
|
||||
});
|
||||
|
||||
test('should render custom cancel text when prop is provided with action sheet interface', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-select label="Fruit" interface="action-sheet" value="bananas" cancel-text="Close me">
|
||||
<ion-select-option value="apples">Apples</ion-select-option>
|
||||
<ion-select-option value="bananas">Bananas</ion-select-option>
|
||||
<ion-select-option value="oranges">Oranges</ion-select-option>
|
||||
</ion-select>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const select = page.locator('ion-select');
|
||||
const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
|
||||
|
||||
await select.click();
|
||||
await ionActionSheetDidPresent.next();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const actionSheet = page.locator('ion-action-sheet');
|
||||
const cancelButton = actionSheet.locator('.action-sheet-cancel');
|
||||
|
||||
// Verify the cancel button text
|
||||
await expect(cancelButton).toHaveText('Close me');
|
||||
});
|
||||
|
||||
test('should render custom cancel text when prop is provided with modal interface', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/30295',
|
||||
});
|
||||
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-select label="Fruit" interface="modal" value="bananas" cancel-text="Close me">
|
||||
<ion-select-option value="apples">Apples</ion-select-option>
|
||||
<ion-select-option value="bananas">Bananas</ion-select-option>
|
||||
<ion-select-option value="oranges">Oranges</ion-select-option>
|
||||
</ion-select>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const select = page.locator('ion-select');
|
||||
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
|
||||
|
||||
await select.click();
|
||||
await ionModalDidPresent.next();
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const modal = page.locator('ion-modal');
|
||||
const cancelButton = modal.locator('ion-button');
|
||||
|
||||
// Verify the cancel button text
|
||||
await expect(cancelButton).toHaveText('Close me');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||