feat(select): add focus on tab (#30076)
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 new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Added focus styles on tab for the ion-select, using the --highlight variable. - Adjusted highlight tests to work for ionic as well, just for the outline type. - Fixed select border-color token used and updated snapshots (this affected all ionic theme snapshots for select). Although not directly related to focus task, the incorrect color was making it very hard to see the differences between the focus colors. ## 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/docs/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. --> - [Select focus](https://ionic-framework-git-rou-11445-select-ionic1.vercel.app/src/components/select/test/highlight?ionic:theme=ionic) --------- Co-authored-by: ionitron <hi@ionicframework.com> Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
@ -50,3 +50,23 @@
|
|||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Focus
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
:host(.ion-focused.select-fill-outline) {
|
||||||
|
--border-color: var(--highlight-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.ion-focused.select-fill-outline:not(.ion-invalid):not(.ion-valid)) {
|
||||||
|
--border-width: #{globals.$ion-border-size-050};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the select has a validity state, the
|
||||||
|
* border should reflect that as a color.
|
||||||
|
*/
|
||||||
|
:host(.has-focus.select-fill-outline.ion-valid),
|
||||||
|
:host(.select-fill-outline.ion-touched.ion-invalid) {
|
||||||
|
--border-color: var(--highlight-color);
|
||||||
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
--background: #{globals.$ion-primitives-base-white};
|
--background: #{globals.$ion-primitives-base-white};
|
||||||
// TODO(ROU-10778, ROU-10875): Sync the color names to the design system of
|
// TODO(ROU-10778, ROU-10875): Sync the color names to the design system of
|
||||||
// ios and md. This will allow us to have a single color map.
|
// ios and md. This will allow us to have a single color map.
|
||||||
--border-color: #{globals.current-color(neutral)};
|
--border-color: #{globals.$ion-primitives-neutral-500};
|
||||||
--border-width: #{globals.$ion-border-size-025};
|
--border-width: #{globals.$ion-border-size-025};
|
||||||
--padding-start: #{globals.$ion-space-400};
|
--padding-start: #{globals.$ion-space-400};
|
||||||
--padding-end: #{globals.$ion-space-400};
|
--padding-end: #{globals.$ion-space-400};
|
||||||
@ -17,6 +17,9 @@
|
|||||||
--padding-bottom: #{globals.$ion-space-300};
|
--padding-bottom: #{globals.$ion-space-300};
|
||||||
--placeholder-color: #{globals.$ion-primitives-neutral-800};
|
--placeholder-color: #{globals.$ion-primitives-neutral-800};
|
||||||
--placeholder-opacity: 1;
|
--placeholder-opacity: 1;
|
||||||
|
--highlight-color-focused: #{globals.$ion-border-focus-default};
|
||||||
|
--highlight-color-valid: #{globals.$ion-semantics-success-900};
|
||||||
|
--highlight-color-invalid: #{globals.$ion-semantics-danger-800};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select Label
|
// Select Label
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -149,6 +149,53 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
|||||||
await expect(container).toHaveScreenshot(screenshot(`select-solid-custom-highlight`));
|
await expect(container).toHaveScreenshot(screenshot(`select-solid-custom-highlight`));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe(title('select: expanded highlight'), () => {
|
||||||
|
test.describe('select: no fill', () => {
|
||||||
|
test('should render bottom highlight', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-select label="Label" class="select-expanded"></ion-select>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const select = page.locator('ion-select');
|
||||||
|
await expect(select).toHaveScreenshot(screenshot(`select-no-fill-highlight`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test.describe('select: solid', () => {
|
||||||
|
test('should render bottom highlight', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-select fill="solid" label="Label" class="select-expanded"></ion-select>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const select = page.locator('ion-select');
|
||||||
|
await expect(select).toHaveScreenshot(screenshot(`select-solid-highlight`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test.describe('select: outline', () => {
|
||||||
|
test('should render bottom highlight', async ({ page }) => {
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<ion-select fill="outline" label="Label" class="select-expanded"></ion-select>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const select = page.locator('ion-select');
|
||||||
|
await expect(select).toHaveScreenshot(screenshot(`select-outline-highlight`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
configs({ modes: ['md', 'ionic-md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||||
|
test.describe(title('select: highlights'), () => {
|
||||||
test.describe('select: outline', () => {
|
test.describe('select: outline', () => {
|
||||||
test('should render valid state correctly', async ({ page }) => {
|
test('should render valid state correctly', async ({ page }) => {
|
||||||
await page.setContent(
|
await page.setContent(
|
||||||
@ -223,46 +270,4 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe(title('select: expanded highlight'), () => {
|
|
||||||
test.describe('select: no fill', () => {
|
|
||||||
test('should render bottom highlight', async ({ page }) => {
|
|
||||||
await page.setContent(
|
|
||||||
`
|
|
||||||
<ion-select label="Label" class="select-expanded"></ion-select>
|
|
||||||
`,
|
|
||||||
config
|
|
||||||
);
|
|
||||||
|
|
||||||
const select = page.locator('ion-select');
|
|
||||||
await expect(select).toHaveScreenshot(screenshot(`select-no-fill-highlight`));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test.describe('select: solid', () => {
|
|
||||||
test('should render bottom highlight', async ({ page }) => {
|
|
||||||
await page.setContent(
|
|
||||||
`
|
|
||||||
<ion-select fill="solid" label="Label" class="select-expanded"></ion-select>
|
|
||||||
`,
|
|
||||||
config
|
|
||||||
);
|
|
||||||
|
|
||||||
const select = page.locator('ion-select');
|
|
||||||
await expect(select).toHaveScreenshot(screenshot(`select-solid-highlight`));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test.describe('select: outline', () => {
|
|
||||||
test('should render bottom highlight', async ({ page }) => {
|
|
||||||
await page.setContent(
|
|
||||||
`
|
|
||||||
<ion-select fill="outline" label="Label" class="select-expanded"></ion-select>
|
|
||||||
`,
|
|
||||||
config
|
|
||||||
);
|
|
||||||
|
|
||||||
const select = page.locator('ion-select');
|
|
||||||
await expect(select).toHaveScreenshot(screenshot(`select-outline-highlight`));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |