fix(input): implement default shape for ionic theme (#29469)
Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
@ -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();
|
||||
|
||||
@ -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`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
63
core/src/components/input/test/shape/index.html
Normal 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>
|
||||
111
core/src/components/input/test/shape/input.e2e.ts
Normal 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`));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |