fix(input): implement default shape for ionic theme (#29469)

Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
This commit is contained in:
Maria Hutt
2024-05-08 13:21:52 -07:00
committed by GitHub
parent fd14ddfec7
commit 7333376506
76 changed files with 207 additions and 69 deletions

View File

@ -514,6 +514,27 @@ export class Input implements ComponentInterface {
return size;
}
private getShape() {
const theme = getIonTheme(this);
const { shape } = this;
if (theme === 'ios' && shape === 'round') {
printIonWarning(`The "${shape}" shape is not supported in the ${theme} theme.`);
return undefined;
}
if (shape !== undefined) {
return shape;
}
// TODO(FW-6229): Update this when the default shape has been decided.
if (theme !== 'ionic') {
return undefined;
}
// Fallback to round shape, which is the default shape for the ionic theme.
return 'round';
}
private onInput = (ev: InputEvent | Event) => {
const input = ev.target as HTMLInputElement | null;
if (input) {
@ -734,10 +755,11 @@ export class Input implements ComponentInterface {
}
render() {
const { disabled, fill, readonly, shape, inputId, el, hasFocus, clearInput, clearInputIcon } = this;
const { disabled, fill, readonly, inputId, el, hasFocus, clearInput, clearInputIcon } = this;
const theme = getIonTheme(this);
const value = this.getValue();
const size = this.getSize();
const shape = this.getShape();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = (theme === 'md' || theme === 'ionic') && fill !== 'outline' && !inItem;
const labelPlacement = this.getLabelPlacement();

View File

@ -44,38 +44,17 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-solid-label-floating`));
});
test('should not have visual regressions with shaped solid', async ({ page }) => {
await page.setContent(
`
<ion-input
shape="round"
fill="solid"
label="Email"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-shaped-solid`));
});
test('padding and border radius should be customizable', async ({ page }) => {
test('padding should be customizable', async ({ page }) => {
await page.setContent(
`
<style>
ion-input {
--border-radius: 10px !important;
--padding-start: 50px !important;
--padding-end: 50px !important;
}
</style>
<ion-input
shape="round"
fill="solid"
label="Email"
label-placement="floating"
@ -89,7 +68,7 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-shaped-solid-custom`));
await expect(input).toHaveScreenshot(screenshot(`input-fill-solid-custom`));
});
});
test.describe('input: fill outline', () => {
@ -130,41 +109,23 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-label-floating`));
});
test('should not have visual regressions with shaped outline', async ({ page }) => {
await page.setContent(
`
<ion-input
shape="round"
fill="outline"
label="Email"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-shaped-outline`));
});
test('padding and border radius should be customizable', async ({ page }) => {
test.only('padding should be customizable', async ({ page }) => {
/**
* Requires padding at the top to prevent the label
* from being clipped by the top of the input.
*/
await page.setContent(
`
<style>
ion-input {
--border-radius: 10px !important;
--padding-start: 50px !important;
--padding-end: 50px !important;
}
</style>
<ion-input
shape="round"
fill="outline"
label="Email"
label-placement="floating"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
@ -175,7 +136,7 @@ configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-shaped-outline-custom`));
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-custom`));
});
});
});
@ -268,7 +229,7 @@ configs({ modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-label-stacked`));
});
test('should not have visual regressions with outline fill and round shape', async ({ page }) => {
test('should not have visual regressions with outline fill and large size', async ({ page }) => {
await page.setContent(
`
<ion-input
@ -276,25 +237,6 @@ configs({ modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
label="Email"
label-placement="stacked"
placeholder="example@ionic.io"
shape="round"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-label-stacked-shape-round`));
});
test('should not have visual regressions with outline fill, round shape, and large size', async ({ page }) => {
await page.setContent(
`
<ion-input
fill="outline"
label="Email"
label-placement="stacked"
placeholder="example@ionic.io"
shape="round"
size="large"
></ion-input>
`,
@ -302,7 +244,7 @@ configs({ modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-label-stacked-shape-round-size-large`));
await expect(input).toHaveScreenshot(screenshot(`input-fill-outline-label-stacked-size-large`));
});
});
});

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Input - Shape</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>
<style>
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(250px, 1fr));
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
}
@media screen and (max-width: 800px) {
.grid {
grid-template-columns: 1fr;
padding: 0;
}
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Input - Shape</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content" class="ion-padding">
<div class="grid">
<div class="grid-item">
<h2>Default Shape</h2>
<ion-input fill="outline" label="Email"></ion-input>
</div>
<div class="grid-item">
<h2>Round Shape</h2>
<ion-input fill="outline" shape="round" label="Email"></ion-input>
</div>
</div>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,111 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['md'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('input: shape'), () => {
/**
* Solid fill is only available in MD theme.
*/
test.describe('solid fill', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-input
shape="round"
fill="solid"
label="Email"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-shape-round-fill-solid`));
});
test('border radius should be customizable', async ({ page }) => {
await page.setContent(
`
<style>
ion-input {
--border-radius: 10px !important;
}
</style>
<ion-input
shape="round"
fill="solid"
label="Email"
label-placement="floating"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-shape-round-fill-solid-custom`));
});
});
});
});
configs({ modes: ['ionic-md', 'md'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('input: shape'), () => {
test.describe('round shape', () => {
test.describe('outline fill', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-input
shape="round"
fill="outline"
label="Email"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-shape-round-fill-outline`));
});
test('border radius should be customizable', async ({ page }) => {
await page.setContent(
`
<style>
ion-input {
--border-radius: 10px !important;
}
</style>
<ion-input
shape="round"
fill="outline"
label="Email"
value="hi@ionic.io"
helper-text="Enter your email"
maxlength="20"
counter="true"
></ion-input>
`,
config
);
const input = page.locator('ion-input');
await expect(input).toHaveScreenshot(screenshot(`input-shape-round-fill-outline-custom`));
});
});
});
});
});