Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme): improved color contrast with color palette #28791

Merged
merged 14 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
16 changes: 15 additions & 1 deletion BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
## Version 8.x

- [Browser and Platform Support](#version-8x-browser-platform-support)
- [Global Styles](#global-styles)
- [Components](#version-8x-components)
- [Button](#version-8x-button)
- [Content](#version-8x-content)
Expand Down Expand Up @@ -45,6 +46,18 @@ This section details the desktop browser, JavaScript framework, and mobile platf
| iOS | 15+ |
| Android | 5.1+ with Chromium 89+ |

<h2 id="version-8x-global-styles">Global Styles</h2>

The `core.css` file has been updated to set the text color on the `body` element:

```diff
body {
+ color: var(--ion-text-color);
}
```

This allows components to inherit the color properly when used outside of Ionic Framework and is required for custom themes to work properly. However, it may have unintentional side effects in apps if the color was not expected to inherit.

<h2 id="version-8x-components">Components</h2>

<h4 id="version-8x-button">Button</h4>
Expand All @@ -66,8 +79,9 @@ This section details the desktop browser, JavaScript framework, and mobile platf
+ background: red;
}
```

<h4 id="version-8x-picker">Picker</h4>

- `ion-picker` and `ion-picker-column` have been renamed to `ion-picker-legacy` and `ion-picker-legacy-column`, respectively. This change was made to accommodate the new inline picker component while allowing developers to continue to use the legacy picker during this migration period.
- Only the component names have been changed. Usages such as `ion-picker` or `IonPicker` should be changed to `ion-picker-legacy` and `IonPickerLegacy`, respectively.
- Non-component usages such as `pickerController` or `useIonPicker` remain unchanged. The new picker displays inline with your page content and does not have equivalents for these non-component usages.
- Non-component usages such as `pickerController` or `useIonPicker` remain unchanged. The new picker displays inline with your page content and does not have equivalents for these non-component usages.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 30 additions & 16 deletions core/src/components/action-sheet/test/a11y/action-sheet.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,40 @@ const testAriaButton = async (
await expect(actionSheetButton).toHaveAttribute('aria-label', expectedAriaLabel);
};

configs({ directions: ['ltr'], themes: ['dark', 'light'] }).forEach(({ config, title }) => {
test.describe(title('action-sheet: Axe testing'), () => {
test('should not have accessibility violations when header is defined', async ({ page }) => {
await page.setContent(
`
<ion-action-sheet></ion-action-sheet>

<script>
const actionSheet = document.querySelector('ion-action-sheet');
actionSheet.header = 'Header';
actionSheet.subHeader = 'Subtitle';
actionSheet.buttons = ['Confirm'];
</script>
`,
config
);

const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
const actionSheet = page.locator('ion-action-sheet');

await actionSheet.evaluate((el: HTMLIonActionSheetElement) => el.present());
await ionActionSheetDidPresent.next();

const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});
});

configs({ directions: ['ltr'] }).forEach(({ config, title }) => {
test.describe(title('action-sheet: a11y'), () => {
test.describe(title('action-sheet: aria attributes'), () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/action-sheet/test/a11y`, config);
});
test('should not have accessibility violations when header is defined', async ({ page }) => {
const button = page.locator('#bothHeaders');
const didPresent = await page.spyOnEvent('ionActionSheetDidPresent');

await button.click();
await didPresent.next();

/**
* action-sheet overlays the entire screen, so
* Axe will be unable to verify color contrast
* on elements under the backdrop.
*/
const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze();
expect(results.violations).toEqual([]);
});

test('should have aria-labelledby when header is set', async ({ page }) => {
await testAria(page, 'bothHeaders', 'action-sheet-1-header');
Expand Down
40 changes: 29 additions & 11 deletions core/src/components/alert/test/a11y/alert.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,35 @@ const testAria = async (
expect(ariaDescribedBy).toBe(expectedAriaDescribedBy);
};

configs({ directions: ['ltr'], themes: ['dark', 'light'] }).forEach(({ title, config }) => {
test.describe(title('alert: Axe testing'), () => {
test('should not have accessibility violations when header and message are defined', async ({ page }) => {
await page.setContent(
`
<ion-alert></ion-alert>

<script>
const alert = document.querySelector('ion-alert');
alert.header = 'Header';
alert.subHeader = 'Subtitle';
alert.buttons = ['OK'];
</script>
`,
config
);

const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
const alert = page.locator('ion-alert');

await alert.evaluate((el: HTMLIonAlertElement) => el.present());
await ionAlertDidPresent.next();

const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});
});

configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('alert: text wrapping'), () => {
test('should break on words and white spaces for radios', async ({ page }, testInfo) => {
Expand Down Expand Up @@ -94,17 +123,6 @@ configs({ directions: ['ltr'] }).forEach(({ config, title }) => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/alert/test/a11y`, config);
});
test('should not have accessibility violations when header and message are defined', async ({ page }) => {
const didPresent = await page.spyOnEvent('ionAlertDidPresent');
const button = page.locator('#bothHeaders');
await button.click();

await didPresent.next();

// TODO FW-4375
const results = await new AxeBuilder({ page }).disableRules('color-contrast').analyze();
expect(results.violations).toEqual([]);
});

test('should have aria-labelledby when header is set', async ({ page }) => {
await testAria(page, 'noMessage', 'alert-1-hdr', null);
Expand Down
26 changes: 26 additions & 0 deletions core/src/components/back-button/test/a11y/back-button.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* Only ios mode uses ion-color() for the back button
*/
configs({ directions: ['ltr'], modes: ['ios'], themes: ['light', 'dark'] }).forEach(({ title, config }) => {
test.describe(title('back-button: a11y for ion-color()'), () => {
test('should not have accessibility violations', async ({ page }) => {
await page.setContent(
`
<style>
ion-back-button {
display: inline-block !important;
vertical-align: middle;
}
</style>
<ion-back-button text="Back" aria-label="back button"></ion-back-button>
`,
config
);

const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});
});

configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('back-button: font scaling'), () => {
test('should scale text on larger font sizes', async ({ page }) => {
Expand Down
24 changes: 24 additions & 0 deletions core/src/components/badge/test/a11y/badge.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

Expand All @@ -23,3 +24,26 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
});
});
});

configs({ directions: ['ltr'], themes: ['light', 'dark'] }).forEach(({ config, title }) => {
test.describe(title('badge: a11y'), () => {
test('should not have accessibility violations', async ({ page }) => {
/**
* All page content should be contained by landmarks (main, nav, etc.)
* By containing the badge in a main element, we can avoid this violation.
*/
await page.setContent(
`
<main>
<ion-badge>123</ion-badge>
</main>
`,
config
);

const results = await new AxeBuilder({ page }).analyze();

expect(results.violations).toEqual([]);
});
});
});