fix(input): match valid state to ionic design (#29277)
Co-authored-by: Sean Perkins <13732623+sean-perkins@users.noreply.github.com> Co-authored-by: ionitron <hi@ionicframework.com>
@ -20,6 +20,16 @@
|
|||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.input-fill-outline.input-shape-round) .input-bottom,
|
||||||
|
:host(.input-fill-outline.input-label-placement-floating) .input-bottom {
|
||||||
|
/**
|
||||||
|
* The bottom content should take on the start and end
|
||||||
|
* padding so it is always aligned with either the label
|
||||||
|
* or the start of the text input.
|
||||||
|
*/
|
||||||
|
@include padding-horizontal(var(--padding-start), var(--padding-end));
|
||||||
|
}
|
||||||
|
|
||||||
:host(.input-fill-outline) .input-wrapper {
|
:host(.input-fill-outline) .input-wrapper {
|
||||||
/**
|
/**
|
||||||
* For the ionic theme, the padding needs to sit on the
|
* For the ionic theme, the padding needs to sit on the
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
:host {
|
:host {
|
||||||
--border-width: #{$ionic-border-size-small};
|
--border-width: #{$ionic-border-size-small};
|
||||||
--border-color: #{$ionic-color-neutral-300};
|
--border-color: #{$ionic-color-neutral-300};
|
||||||
|
--highlight-color-valid: #{$ionic-color-success-400};
|
||||||
--highlight-color-invalid: #{$ionic-color-error-400};
|
--highlight-color-invalid: #{$ionic-color-error-400};
|
||||||
--text-color-invalid: #{$ionic-color-error-600};
|
--text-color-invalid: #{$ionic-color-error-600};
|
||||||
}
|
}
|
||||||
@ -20,6 +21,16 @@
|
|||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input Bottom Content
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
.input-bottom {
|
||||||
|
@include padding-horizontal(0, 0);
|
||||||
|
|
||||||
|
// TODO(FW-6112): Update it to `$ionic-font-weight-medium` when it's available
|
||||||
|
font-weight: var(--ionic-font-weight-medium, 500);
|
||||||
|
}
|
||||||
|
|
||||||
// Input Hint Text
|
// Input Hint Text
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
@ -27,6 +38,10 @@
|
|||||||
color: tokens.$ionic-color-neutral-600;
|
color: tokens.$ionic-color-neutral-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(.has-focus.ion-valid) .helper-text {
|
||||||
|
color: #{tokens.$ionic-color-success-800};
|
||||||
|
}
|
||||||
|
|
||||||
:host(.ion-touched.ion-invalid) .error-text {
|
:host(.ion-touched.ion-invalid) .error-text {
|
||||||
color: var(--text-color-invalid);
|
color: var(--text-color-invalid);
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 978 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 922 B After Width: | Height: | Size: 927 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 935 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 887 B After Width: | Height: | Size: 892 B |
|
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 973 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 868 B After Width: | Height: | Size: 918 B |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.4 KiB |
@ -348,6 +348,25 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
|||||||
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
|
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
|
||||||
test.describe(title('input: highlights'), () => {
|
test.describe(title('input: highlights'), () => {
|
||||||
test.describe('input: no fill', () => {
|
test.describe('input: no fill', () => {
|
||||||
|
test('should render valid state correctly', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-input
|
||||||
|
value="hi@ionic.io"
|
||||||
|
class="ion-valid has-focus"
|
||||||
|
label="Email"
|
||||||
|
error-text="Please enter a valid email"
|
||||||
|
helper-text="Enter an email"
|
||||||
|
counter="true"
|
||||||
|
maxlength="20"
|
||||||
|
></ion-input>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const input = page.locator('ion-input');
|
||||||
|
await expect(input).toHaveScreenshot(screenshot(`input-no-fill-valid`));
|
||||||
|
});
|
||||||
test('should render invalid state correctly', async ({ page }) => {
|
test('should render invalid state correctly', async ({ page }) => {
|
||||||
await page.setContent(
|
await page.setContent(
|
||||||
`
|
`
|
||||||
@ -369,6 +388,26 @@ configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screensh
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
test.describe('input: outline', () => {
|
test.describe('input: outline', () => {
|
||||||
|
test('should render valid state correctly', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-input
|
||||||
|
fill="outline"
|
||||||
|
value="hi@ionic.io"
|
||||||
|
class="ion-valid has-focus"
|
||||||
|
label="Email"
|
||||||
|
error-text="Please enter a valid email"
|
||||||
|
helper-text="Enter an email"
|
||||||
|
counter="true"
|
||||||
|
maxlength="20"
|
||||||
|
></ion-input>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const input = page.locator('ion-input');
|
||||||
|
await expect(input).toHaveScreenshot(screenshot(`input-outline-valid`));
|
||||||
|
});
|
||||||
test('should render invalid state correctly', async ({ page }) => {
|
test('should render invalid state correctly', async ({ page }) => {
|
||||||
await page.setContent(
|
await page.setContent(
|
||||||
`
|
`
|
||||||
@ -389,6 +428,34 @@ configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screensh
|
|||||||
const input = page.locator('ion-input');
|
const input = page.locator('ion-input');
|
||||||
await expect(input).toHaveScreenshot(screenshot(`input-outline-invalid`));
|
await expect(input).toHaveScreenshot(screenshot(`input-outline-invalid`));
|
||||||
});
|
});
|
||||||
|
test('should render custom highlight correctly', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<style>
|
||||||
|
ion-input.custom {
|
||||||
|
--highlight-color-valid: purple;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<ion-input
|
||||||
|
fill="outline"
|
||||||
|
value="hi@ionic.io"
|
||||||
|
class="custom has-focus ion-valid"
|
||||||
|
label="Email"
|
||||||
|
error-text="Please enter a valid email"
|
||||||
|
helper-text="Enter an email"
|
||||||
|
counter="true"
|
||||||
|
maxlength="20"
|
||||||
|
></ion-input>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const container = page.locator('.container');
|
||||||
|
await expect(container).toHaveScreenshot(screenshot(`input-outline-custom-highlight`));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 3.4 KiB |