feat(item): support dynamic type (#27989)
Adds support for dynamic type by converting `font-size` to use `rem` units and icon `font-size` to use `em` units.
@@ -1,3 +1,4 @@
|
||||
@use "sass:math";
|
||||
@import "./item-divider";
|
||||
@import "./item-divider.md.vars";
|
||||
|
||||
@@ -14,7 +15,7 @@
|
||||
|
||||
border-bottom: $item-divider-md-border-bottom;
|
||||
|
||||
font-size: $item-divider-md-font-size;
|
||||
font-size: dynamic-font($item-divider-md-font-size);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +45,13 @@
|
||||
::slotted(ion-icon) {
|
||||
color: $item-md-icon-slot-color;
|
||||
|
||||
font-size: $item-md-icon-slot-font-size;
|
||||
// The icon's font size should use em units to support
|
||||
// font scaling but evaluate to 24px at 100% font size.
|
||||
// The value in em units is calculated by dividing
|
||||
// the icon's font size in pixels by the item divider's
|
||||
// font size in pixels.
|
||||
// e.g. 24px / 14px = 1.7142857143em
|
||||
font-size: math.div($item-md-icon-slot-font-size, $item-divider-md-font-size) * 1em;
|
||||
}
|
||||
|
||||
:host(.ion-color) ::slotted(ion-icon) {
|
||||
|
||||
@@ -14,7 +14,7 @@ $item-divider-md-color: $text-color-step-600 !default;
|
||||
$item-divider-md-background: $background-color !default;
|
||||
|
||||
/// @prop - Font size for the divider
|
||||
$item-divider-md-font-size: 0.875rem !default;
|
||||
$item-divider-md-font-size: 14px !default;
|
||||
|
||||
/// @prop - Border bottom for the divider
|
||||
$item-divider-md-border-bottom: 1px solid $item-md-border-color !default;
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -161,7 +161,7 @@
|
||||
|
||||
min-height: 24px;
|
||||
|
||||
font-size: 13px;
|
||||
font-size: dynamic-font(13px);
|
||||
}
|
||||
|
||||
// iOS Item Avatar
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
$item-ios-min-height: 44px !default;
|
||||
|
||||
/// @prop - Font size of the item
|
||||
$item-ios-font-size: 16px !default;
|
||||
$item-ios-font-size: dynamic-font(16px) !default;
|
||||
|
||||
/// @prop - Margin top of the item paragraph
|
||||
$item-ios-paragraph-margin-top: 0 !default;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use "sass:math";
|
||||
@import "./item";
|
||||
@import "./item.md.vars";
|
||||
@import "../label/label.md.vars";
|
||||
@@ -25,7 +26,7 @@
|
||||
--highlight-color-valid: #{$item-md-input-highlight-color-valid};
|
||||
--highlight-color-invalid: #{$item-md-input-highlight-color-invalid};
|
||||
|
||||
font-size: $item-md-font-size;
|
||||
font-size: dynamic-font($item-md-font-size);
|
||||
font-weight: normal;
|
||||
|
||||
text-transform: none;
|
||||
@@ -201,7 +202,13 @@
|
||||
::slotted(ion-icon) {
|
||||
color: $item-md-icon-slot-color;
|
||||
|
||||
font-size: $item-md-icon-slot-font-size;
|
||||
// The icon's font size should use em units to support
|
||||
// font scaling but evaluate to 24px at 100% font size.
|
||||
// The value in em units is calculated by dividing
|
||||
// the icon's font size in pixels by the item's
|
||||
// font size in pixels.
|
||||
// e.g. 24px / 16px = 1.5em
|
||||
font-size: math.div($item-md-icon-slot-font-size, $item-md-font-size) * 1em;
|
||||
}
|
||||
|
||||
:host(.ion-color:not(.item-fill-solid):not(.item-fill-outline)) ::slotted(ion-icon) {
|
||||
@@ -338,7 +345,7 @@
|
||||
|
||||
min-height: 25px;
|
||||
|
||||
font-size: 12px;
|
||||
font-size: dynamic-font(12px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ $item-md-icon-end-slot-margin-end: null !default;
|
||||
$item-md-icon-slot-color: rgba($text-color-rgb, 0.54) !default;
|
||||
|
||||
/// @prop - Font size of an icon in the start/end slot
|
||||
$item-md-icon-slot-font-size: 24px !default;
|
||||
$item-md-icon-slot-font-size: 24px !default;
|
||||
|
||||
|
||||
// Label Slots
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
--show-full-highlight: 0;
|
||||
--show-inset-highlight: 0;
|
||||
--detail-icon-color: initial;
|
||||
--detail-icon-font-size: 20px;
|
||||
--detail-icon-font-size: 1.25em;
|
||||
--detail-icon-opacity: 0.25;
|
||||
--color-activated: var(--color);
|
||||
--color-focused: var(--color);
|
||||
@@ -573,7 +573,7 @@ ion-ripple-effect {
|
||||
.item-counter {
|
||||
padding-top: 5px;
|
||||
|
||||
font-size: 12px;
|
||||
font-size: dynamic-font(12px);
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import AxeBuilder from '@axe-core/playwright';
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs().forEach(({ title, config }) => {
|
||||
configs({ directions: ['ltr'] }).forEach(({ config, screenshot, title }) => {
|
||||
test.describe(title('item: axe'), () => {
|
||||
test('should not have accessibility violations', async ({ page }) => {
|
||||
await page.goto(`/src/components/item/test/a11y`, config);
|
||||
@@ -30,4 +30,150 @@ configs().forEach(({ title, config }) => {
|
||||
expect(await item2.getAttribute('aria-label')).toEqual('test');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe(title('item: font scaling'), () => {
|
||||
test('should scale text on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item</ion-label>
|
||||
</ion-item>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const item = page.locator('ion-item');
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot(`item-scale`));
|
||||
});
|
||||
test('should scale slotted icons on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-item>
|
||||
<ion-icon slot="start" name="star"></ion-icon>
|
||||
<ion-label>Item</ion-label>
|
||||
<ion-icon slot="end" name="flag"></ion-icon>
|
||||
</ion-item>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const item = page.locator('ion-item');
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot(`item-icons-scale`));
|
||||
});
|
||||
test('should scale detail icon on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-item detail="true">
|
||||
<ion-label>Item</ion-label>
|
||||
</ion-item>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const item = page.locator('ion-item');
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot(`item-detail-icon-scale`));
|
||||
});
|
||||
test('should scale counter text on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-item counter="true">
|
||||
<ion-label position="stacked">Counter</ion-label>
|
||||
<ion-input maxlength="20"></ion-input>
|
||||
</ion-item>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const item = page.locator('ion-item');
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot(`item-counter-text-scale`));
|
||||
});
|
||||
test('should scale helper and error text on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Helper</ion-label>
|
||||
<ion-input></ion-input>
|
||||
<ion-note slot="helper">Helper Text</ion-note>
|
||||
</ion-item>
|
||||
<ion-item class="ion-invalid">
|
||||
<ion-label>Error</ion-label>
|
||||
<ion-input></ion-input>
|
||||
<ion-note slot="error">Error Text</ion-note>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot(`item-helper-error-text-scale`));
|
||||
});
|
||||
test('should scale buttons in an item on larger font sizes', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
html {
|
||||
font-size: 310%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Item</ion-label>
|
||||
<ion-button>Default</ion-button>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item</ion-label>
|
||||
<ion-button size="small">Small</ion-button>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Item</ion-label>
|
||||
<ion-button size="large">Large</ion-button>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot(`item-buttons-scale`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 8.5 KiB |