feat(input,textarea,select): add --highlight-height variable (#29090)
Issue number: Internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> In v7, using the legacy syntax, the height of the highlight on an item could be adjusted using the `--highlight-height` variable. This variable was not added to input and therefore would not work using the modern syntax. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> Adds the `--highlight-height` variable to `ion-input`, `ion-textarea` and `ion-select` so that developers can customize this height in `md` mode. Since the highlight element is not added for `ios` mode, this variable won't do anything for `ios`. Note that this diverges from the v7 behavior, where setting `--highlight-height` enabled the highlight for `ios`. A design document outlining this has been proposed here: https://github.com/ionic-team/ionic-framework-design-documents/pull/252 ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
@ -4,6 +4,10 @@
|
||||
// iOS Select
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
--highlight-height: 0px;
|
||||
}
|
||||
|
||||
.select-icon {
|
||||
width: $select-ios-icon-size;
|
||||
height: $select-ios-icon-size;
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
*/
|
||||
:host(.select-fill-outline.select-expanded),
|
||||
:host(.select-fill-outline.ion-focused) {
|
||||
--border-width: 2px;
|
||||
--border-width: var(--highlight-height);
|
||||
--border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
:host {
|
||||
--border-width: 1px;
|
||||
--border-color: #{$item-md-border-color};
|
||||
--highlight-height: 2px;
|
||||
}
|
||||
|
||||
.select-icon {
|
||||
@ -50,7 +51,7 @@
|
||||
position: absolute;
|
||||
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
height: var(--highlight-height);
|
||||
|
||||
transform: scale(0);
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
* @prop --placeholder-color: Color of the select placeholder text
|
||||
* @prop --placeholder-opacity: Opacity of the select placeholder text
|
||||
*
|
||||
* @prop --highlight-height: The height of the highlight on the select. Only applies to md mode.
|
||||
* @prop --highlight-color-focused: The color of the highlight on the select when focused
|
||||
* @prop --highlight-color-invalid: The color of the highlight on the select when invalid
|
||||
* @prop --highlight-color-valid: The color of the highlight on the select when valid
|
||||
|
||||
@ -33,6 +33,13 @@
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.custom {
|
||||
--highlight-color-focused: purple;
|
||||
--highlight-color-invalid: purple;
|
||||
--highlight-color-valid: purple;
|
||||
--highlight-height: 6px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -117,6 +124,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>No Fill, Custom</h1>
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Focus</h2>
|
||||
<ion-select label-placement="start" value="hi@ionic.io" class="custom ion-focused" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Valid, Focus</h2>
|
||||
<ion-select label-placement="start" class="custom ion-valid ion-focused" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Invalid</h2>
|
||||
<ion-select label-placement="start" class="custom ion-touched ion-invalid" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Solid, Default</h1>
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
@ -189,6 +220,36 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Solid, Custom</h1>
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Focus</h2>
|
||||
<ion-select
|
||||
fill="solid"
|
||||
label-placement="start"
|
||||
value="hi@ionic.io"
|
||||
class="custom ion-focused"
|
||||
label="Fruit"
|
||||
>
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Valid, Focus</h2>
|
||||
<ion-select fill="solid" label-placement="start" class="custom ion-valid ion-focused" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Invalid</h2>
|
||||
<ion-select fill="solid" label-placement="start" class="custom ion-touched ion-invalid" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Outline, Default</h1>
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
@ -260,6 +321,36 @@
|
||||
</ion-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Outline, Custom</h1>
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Focus</h2>
|
||||
<ion-select
|
||||
fill="outline"
|
||||
label-placement="start"
|
||||
value="hi@ionic.io"
|
||||
class="custom ion-focused"
|
||||
label="Fruit"
|
||||
>
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Valid, Focus</h2>
|
||||
<ion-select fill="outline" label-placement="start" class="custom ion-valid ion-focused" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Invalid</h2>
|
||||
<ion-select fill="outline" label-placement="start" class="custom ion-touched ion-invalid" label="Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
@ -2,8 +2,8 @@ import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('input: highlights'), () => {
|
||||
test.describe('input: no fill', () => {
|
||||
test.describe(title('select: highlights'), () => {
|
||||
test.describe('select: no fill', () => {
|
||||
test('should render valid state correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
@ -43,8 +43,40 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
const select = page.locator('ion-select');
|
||||
await expect(select).toHaveScreenshot(screenshot(`select-no-fill-focus`));
|
||||
});
|
||||
test('should render custom highlight correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
ion-select.custom {
|
||||
--highlight-color-focused: red;
|
||||
--highlight-color-invalid: blue;
|
||||
--highlight-color-valid: purple;
|
||||
--highlight-height: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<ion-select value="apple" class="custom ion-valid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select value="apple" class="custom ion-touched ion-invalid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select value="apple" class="custom ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('.container');
|
||||
await expect(container).toHaveScreenshot(screenshot(`select-no-fill-custom-highlight`));
|
||||
});
|
||||
});
|
||||
test.describe('input: solid', () => {
|
||||
test.describe('select: solid', () => {
|
||||
test('should render valid state correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
@ -84,8 +116,40 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
const select = page.locator('ion-select');
|
||||
await expect(select).toHaveScreenshot(screenshot(`select-solid-focus`));
|
||||
});
|
||||
test('should render custom highlight correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
ion-select.custom {
|
||||
--highlight-color-focused: red;
|
||||
--highlight-color-invalid: blue;
|
||||
--highlight-color-valid: purple;
|
||||
--highlight-height: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<ion-select fill="solid" value="apple" class="custom ion-valid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select fill="solid" value="apple" class="custom ion-touched ion-invalid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select fill="solid" value="apple" class="custom ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('.container');
|
||||
await expect(container).toHaveScreenshot(screenshot(`select-solid-custom-highlight`));
|
||||
});
|
||||
});
|
||||
test.describe('input: outline', () => {
|
||||
test.describe('select: outline', () => {
|
||||
test('should render valid state correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
@ -125,6 +189,38 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
||||
const select = page.locator('ion-select');
|
||||
await expect(select).toHaveScreenshot(screenshot(`select-outline-focus`));
|
||||
});
|
||||
test('should render custom highlight correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
ion-select.custom {
|
||||
--highlight-color-focused: red;
|
||||
--highlight-color-invalid: blue;
|
||||
--highlight-color-valid: purple;
|
||||
--highlight-height: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<ion-select fill="outline" value="apple" class="custom ion-valid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select fill="outline" value="apple" class="custom ion-touched ion-invalid ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
|
||||
<ion-select fill="outline" value="apple" class="custom ion-focused" label="Favorite Fruit">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('.container');
|
||||
await expect(container).toHaveScreenshot(screenshot(`select-outline-custom-highlight`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |