feat(chip): add dynamic type support (#27868)

Issue number: N/A

---------

<!-- 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. -->
The chip component does not support dynamic type.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->
The chip component supports dynamic type, has a dynamic height, has min
and max font sizes in `ios` mode, and has a screenshot test.

### md mode

Small md mode:
<img width="1368" alt="md-small"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/4466c1b6-6d01-4ec8-8de9-0eb71fa45223">


Medium md mode:
<img width="1371" alt="md-medium"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/c51c324e-a3b7-486b-9f68-84b0e4146570">


Large md mode:
<img width="1369" alt="md-large"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/166e1229-96b7-4270-9ef2-4c708776691e">


 
### ios mode
Small ios mode:
<img width="1371" alt="ios-small"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/de240058-5fe5-4387-8481-d695950853db">


Medium ios mode:
<img width="1371" alt="ios-medium"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/c63db4be-e813-4917-a525-02ec456849ea">


Large ios mode:
<img width="1370" alt="ios-large"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/3479f619-82c8-4645-85f7-2725ea43de00">



## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

This also fixes an existing bug that the contents of a chip could get
smooshed if the chip doesn't have enough horizontal space for its
contents.

### Before
<img width="253" alt="rStll"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/9a8f4c30-ceef-4fe1-a600-38b2f01c4e68">


### After
<img width="253" alt="Screenshot 2023-08-02 at 5 00 39 PM"
src="https://github.com/ionic-team/ionic-framework/assets/14926794/e82e17c3-91e3-4089-a57b-16c7d7b386fb">

---------

Co-authored-by: ionitron <hi@ionicframework.com>
Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
This commit is contained in:
Shawn Taylor
2023-08-08 11:04:51 -04:00
committed by GitHub
parent c9b27927bd
commit 8fae6da3f1
15 changed files with 125 additions and 29 deletions

View File

@@ -0,0 +1,11 @@
@import "./chip";
@import "./chip.vars";
:host {
/**
* Main content should be prioritized on iOS,
* so we set max font size for chips.
* We add a min font size to keep the text legible.
*/
font-size: clamp(13px, $chip-base-font-size-rem, 22px);
}

View File

@@ -0,0 +1,6 @@
@import "./chip";
@import "./chip.vars";
:host {
font-size: $chip-base-font-size-rem;
}

View File

@@ -1,17 +1,18 @@
@import "../../themes/ionic.globals";
@import "./chip.vars";
:host {
/**
* @prop --background: Background of the chip
* @prop --color: Color of the chip
*/
--background: #{rgba($text-color-rgb, .12)};
--color: #{rgba($text-color-rgb, .87)};
--background: #{rgba($text-color-rgb, 0.12)};
--color: #{rgba($text-color-rgb, 0.87)};
@include border-radius(16px);
@include font-smoothing();
@include margin(4px);
@include padding(7px, 12px);
@include padding(6px, 12px);
display: inline-flex;
@@ -19,13 +20,12 @@
align-items: center;
height: 32px;
min-height: 32px;
background: var(--background);
color: var(--color);
font-family: $font-family-base;
font-size: 14px;
cursor: pointer;
@@ -37,7 +37,7 @@
:host(.chip-disabled) {
cursor: default;
opacity: .4;
opacity: 0.4;
pointer-events: none;
}
@@ -45,19 +45,18 @@
// ---------------------------------------------
:host(.ion-color) {
background: current-color(base, .08);
background: current-color(base, 0.08);
color: current-color(shade);
}
:host(.ion-color:focus) {
background: current-color(base, .12);
background: current-color(base, 0.12);
}
:host(.ion-color.ion-activated) {
background: current-color(base, .16);
background: current-color(base, 0.16);
}
// Outline Chip
// ---------------------------------------------
@@ -67,33 +66,32 @@
}
:host(.chip-outline) {
border-color: rgba($text-color-rgb, .32);
border-color: rgba($text-color-rgb, 0.32);
background: transparent;
}
:host(.chip-outline.ion-color) {
border-color: current-color(base, .32);
border-color: current-color(base, 0.32);
}
:host(.chip-outline:not(.ion-color):focus) {
background: rgba($text-color-rgb, .04);
background: rgba($text-color-rgb, 0.04);
}
:host(.chip-outline.ion-activated:not(.ion-color)) {
background: rgba($text-color-rgb, .08);
background: rgba($text-color-rgb, 0.08);
}
// Chip Icon
// ---------------------------------------------
::slotted(ion-icon) {
font-size: 20px;
font-size: $chip-icon-size;
}
:host(:not(.ion-color)) ::slotted(ion-icon) {
color: rgba($text-color-rgb, .54);
color: rgba($text-color-rgb, 0.54);
}
::slotted(ion-icon:first-child) {
@@ -104,13 +102,14 @@
@include margin(-4px, -4px, -4px, 8px);
}
// Chip Avatar
// ---------------------------------------------
::slotted(ion-avatar) {
width: 24px;
height: 24px;
flex-shrink: 0;
width: $chip-avatar-size;
height: $chip-avatar-size;
}
::slotted(ion-avatar:first-child) {
@@ -121,7 +120,6 @@
@include margin(-4px, -8px, -4px, 8px);
}
// Chip: Focus
// ---------------------------------------------
@@ -130,31 +128,29 @@
}
:host(:focus) {
--background: #{rgba($text-color-rgb, .16)};
--background: #{rgba($text-color-rgb, 0.16)};
}
// Chip: Activated
// ---------------------------------------------
:host(.ion-activated) {
--background: #{rgba($text-color-rgb, .20)};
--background: #{rgba($text-color-rgb, 0.2)};
}
// Chip: Hover
// ---------------------------------------------
@media (any-hover: hover) {
:host(:hover) {
--background: #{rgba($text-color-rgb, .16)};
--background: #{rgba($text-color-rgb, 0.16)};
}
:host(.ion-color:hover) {
background: current-color(base, .12);
background: current-color(base, 0.12);
}
:host(.chip-outline:not(.ion-color):hover) {
background: rgba($text-color-rgb, .04);
background: rgba($text-color-rgb, 0.04);
}
}

View File

@@ -10,7 +10,10 @@ import { createColorClasses } from '../../utils/theme';
*/
@Component({
tag: 'ion-chip',
styleUrl: 'chip.scss',
styleUrls: {
ios: 'chip.ios.scss',
md: 'chip.md.scss',
},
shadow: true,
})
export class Chip implements ComponentInterface {

View File

@@ -0,0 +1,13 @@
@use "sass:math";
/// @prop - Unitless font size of the chip before scaling
$chip-base-font-size: 14;
/// @prop - Font size of the chip in rem before scaling
$chip-base-font-size-rem: #{math.div($chip-base-font-size, 16)}rem;
/// @prop - Size of an icon within a chip (in em to scale as the font size of the chip scales)
$chip-icon-size: math.div(20em, $chip-base-font-size);
/// @prop - Size of an avatar within a chip (in em to scale as the font size of the chip scales)
$chip-avatar-size: math.div(24em, $chip-base-font-size);

View File

@@ -0,0 +1,67 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
/**
* Font scaling does not vary across directions.
*/
test.describe(title('chip: font scaling'), () => {
test('should scale text', async ({ page }) => {
await page.setContent(
`
<style>
html {
font-size: 30px;
}
</style>
<ion-chip>
<ion-avatar>
<img
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBmaWxsPSIjYzVkYmZmIiBkPSJNMCAwaDUxMnY1MTJIMHoiLz48cGF0aCBkPSJNMjU2IDMwNGM2MS42IDAgMTEyLTUwLjQgMTEyLTExMlMzMTcuNiA4MCAyNTYgODBzLTExMiA1MC40LTExMiAxMTIgNTAuNCAxMTIgMTEyIDExMnptMCA0MGMtNzQuMiAwLTIyNCAzNy44LTIyNCAxMTJ2NTZoNDQ4di01NmMwLTc0LjItMTQ5LjgtMTEyLTIyNC0xMTJ6IiBmaWxsPSIjODJhZWZmIi8+PC9zdmc+"
/>
</ion-avatar>
<ion-label>With Icon and Avatar</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>`,
config
);
const chip = page.locator('ion-chip');
await expect(chip).toHaveScreenshot(screenshot('chip-scale'));
});
});
});
configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, config }) => {
/**
* Font scaling does not vary across directions
* ios mode has a min font size
*/
test.describe(title('chip: contents at large scale'), () => {
test('should handle contents wider than chip', async ({ page }) => {
await page.setContent(
`
<style>
html {
font-size: 48px;
}
</style>
<ion-chip>
<ion-avatar>
<img
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBmaWxsPSIjYzVkYmZmIiBkPSJNMCAwaDUxMnY1MTJIMHoiLz48cGF0aCBkPSJNMjU2IDMwNGM2MS42IDAgMTEyLTUwLjQgMTEyLTExMlMzMTcuNiA4MCAyNTYgODBzLTExMiA1MC40LTExMiAxMTIgNTAuNCAxMTIgMTEyIDExMnptMCA0MGMtNzQuMiAwLTIyNCAzNy44LTIyNCAxMTJ2NTZoNDQ4di01NmMwLTc0LjItMTQ5LjgtMTEyLTIyNC0xMTJ6IiBmaWxsPSIjODJhZWZmIi8+PC9zdmc+"
/>
</ion-avatar>
<ion-label>With Icon and Avatar</ion-label>
<ion-icon name="close-circle"></ion-icon>
</ion-chip>`,
config
);
const chip = page.locator('ion-chip');
await expect(chip).toHaveScreenshot(screenshot('chip-large-contents'));
});
});
});

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB