feat(badge): add soft to the ionic theme (#29573)

Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
This commit is contained in:
Maria Hutt
2024-05-31 11:47:13 -07:00
committed by GitHub
parent e9fd407e90
commit 777521f218
21 changed files with 171 additions and 4 deletions

View File

@ -312,6 +312,7 @@ ion-backdrop,event,ionBackdropTap,void,true
ion-badge,shadow ion-badge,shadow
ion-badge,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true ion-badge,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-badge,prop,mode,"ios" | "md",undefined,false,false ion-badge,prop,mode,"ios" | "md",undefined,false,false
ion-badge,prop,shape,"soft" | undefined,undefined,false,false
ion-badge,prop,size,"large" | "medium" | "small" | "xlarge" | "xsmall" | "xxsmall" | undefined,undefined,false,false ion-badge,prop,size,"large" | "medium" | "small" | "xlarge" | "xsmall" | "xxsmall" | undefined,undefined,false,false
ion-badge,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-badge,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-badge,css-prop,--background,ionic ion-badge,css-prop,--background,ionic

View File

@ -417,6 +417,10 @@ export namespace Components {
* The mode determines the platform behaviors of the component. * The mode determines the platform behaviors of the component.
*/ */
"mode"?: "ios" | "md"; "mode"?: "ios" | "md";
/**
* Set to `"soft"` for slightly rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
*/
"shape"?: 'soft';
/** /**
* Set to `"xxsmall"` for the smallest badge. Set to "xsmall" for a very small badge. Set to `"small"` for a small badge. Set to "medium" for a medium badge. Set to "large" for a large badge. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes. * Set to `"xxsmall"` for the smallest badge. Set to "xsmall" for a very small badge. Set to `"small"` for a small badge. Set to "medium" for a medium badge. Set to "large" for a large badge. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes.
*/ */
@ -5661,6 +5665,10 @@ declare namespace LocalJSX {
* The mode determines the platform behaviors of the component. * The mode determines the platform behaviors of the component.
*/ */
"mode"?: "ios" | "md"; "mode"?: "ios" | "md";
/**
* Set to `"soft"` for slightly rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
*/
"shape"?: 'soft';
/** /**
* Set to `"xxsmall"` for the smallest badge. Set to "xsmall" for a very small badge. Set to `"small"` for a small badge. Set to "medium" for a medium badge. Set to "large" for a large badge. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes. * Set to `"xxsmall"` for the smallest badge. Set to "xsmall" for a very small badge. Set to `"small"` for a small badge. Set to "medium" for a medium badge. Set to "large" for a large badge. Set to `"xlarge"` for the largest badge. Defaults to `"small"` for the `ionic` theme, undefined for all other themes.
*/ */

View File

@ -18,6 +18,20 @@
font-weight: globals.$ionic-font-weight-medium; font-weight: globals.$ionic-font-weight-medium;
} }
// Badge Shapes
// --------------------------------------------------
/* Soft Badge */
:host(.badge-soft) {
@include border-radius(globals.$ionic-border-radius-200);
}
:host(.badge-xxsmall.badge-soft),
:host(.badge-xsmall.badge-soft),
:host(.badge-small.badge-soft) {
@include border-radius(globals.$ionic-border-radius-100);
}
// Badge Sizes // Badge Sizes
// -------------------------------------------------- // --------------------------------------------------

View File

@ -26,6 +26,13 @@ export class Badge implements ComponentInterface {
*/ */
@Prop({ reflect: true }) color?: Color; @Prop({ reflect: true }) color?: Color;
/**
* Set to `"soft"` for slightly rounded corners.
*
* Defaults to `"round"` for the `ionic` theme, undefined for all other themes.
*/
@Prop() shape?: 'soft';
/** /**
* Set to `"xxsmall"` for the smallest badge. * Set to `"xxsmall"` for the smallest badge.
* Set to "xsmall" for a very small badge. * Set to "xsmall" for a very small badge.
@ -38,6 +45,22 @@ export class Badge implements ComponentInterface {
*/ */
@Prop() size?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; @Prop() size?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
private getShape(): string | undefined {
const theme = getIonTheme(this);
const { shape } = this;
// TODO(ROU-10777): Remove theme check when shapes are defined for all themes.
if (theme !== 'ionic') {
return undefined;
}
if (shape === undefined) {
return 'round';
}
return shape;
}
private getSize(): string | undefined { private getSize(): string | undefined {
const theme = getIonTheme(this); const theme = getIonTheme(this);
const { size } = this; const { size } = this;
@ -55,12 +78,14 @@ export class Badge implements ComponentInterface {
} }
render() { render() {
const shape = this.getShape();
const size = this.getSize(); const size = this.getSize();
const theme = getIonTheme(this); const theme = getIonTheme(this);
return ( return (
<Host <Host
class={createColorClasses(this.color, { class={createColorClasses(this.color, {
[theme]: true, [theme]: true,
[`badge-${shape}`]: shape !== undefined,
[`badge-${size}`]: size !== undefined, [`badge-${size}`]: size !== undefined,
})} })}
> >

View File

@ -0,0 +1,77 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* This behavior does not vary across directions.
*/
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('badge: shape'), () => {
test('should render soft badges for smaller sizes', async ({ page }) => {
await page.setContent(
`
<div id="container">
<ion-badge shape="soft" size="xxsmall">1</ion-badge>
<ion-badge shape="soft" size="xsmall">1</ion-badge>
<ion-badge shape="soft" size="small">1</ion-badge>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`badge-shape-soft-smaller-sizes`));
});
test('should render soft badges with long text for smaller sizes', async ({ page }) => {
await page.setContent(
`
<div id="container">
<ion-badge shape="soft" size="xxsmall">99+</ion-badge>
<ion-badge shape="soft" size="xsmall">99+</ion-badge>
<ion-badge shape="soft" size="small">99+</ion-badge>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`badge-shape-soft-smaller-sizes-long-text`));
});
test('should render soft badges for larger sizes', async ({ page }) => {
await page.setContent(
`
<div id="container">
<ion-badge shape="soft" size="medium">1</ion-badge>
<ion-badge shape="soft" size="large">1</ion-badge>
<ion-badge shape="soft" size="xlarge">1</ion-badge>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`badge-shape-soft-larger-sizes`));
});
test('should render soft badges with long text for larger sizes', async ({ page }) => {
await page.setContent(
`
<div id="container">
<ion-badge shape="soft" size="medium">99+</ion-badge>
<ion-badge shape="soft" size="large">99+</ion-badge>
<ion-badge shape="soft" size="xlarge">99+</ion-badge>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`badge-shape-soft-larger-sizes-long-text`));
});
});
});

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Badge - Shape</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Button - Shape</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding" id="content" no-bounce>
<ion-list>
<ion-item>
<ion-label>Default</ion-label>
<ion-badge slot="end">00</ion-badge>
<ion-badge slot="end">99+</ion-badge>
</ion-item>
<ion-item>
<ion-label>Soft</ion-label>
<ion-badge slot="end" shape="soft">1</ion-badge>
<ion-badge slot="end" shape="soft">99+</ion-badge>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -260,14 +260,14 @@ export declare interface IonBackdrop extends Components.IonBackdrop {
@ProxyCmp({ @ProxyCmp({
inputs: ['color', 'mode', 'size', 'theme'] inputs: ['color', 'mode', 'shape', 'size', 'theme']
}) })
@Component({ @Component({
selector: 'ion-badge', selector: 'ion-badge',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>', template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'mode', 'size', 'theme'], inputs: ['color', 'mode', 'shape', 'size', 'theme'],
}) })
export class IonBadge { export class IonBadge {
protected el: HTMLElement; protected el: HTMLElement;

View File

@ -344,14 +344,14 @@ export declare interface IonBackdrop extends Components.IonBackdrop {
@ProxyCmp({ @ProxyCmp({
defineCustomElementFn: defineIonBadge, defineCustomElementFn: defineIonBadge,
inputs: ['color', 'mode', 'size', 'theme'] inputs: ['color', 'mode', 'shape', 'size', 'theme']
}) })
@Component({ @Component({
selector: 'ion-badge', selector: 'ion-badge',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>', template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'mode', 'size', 'theme'], inputs: ['color', 'mode', 'shape', 'size', 'theme'],
standalone: true standalone: true
}) })
export class IonBadge { export class IonBadge {

View File

@ -118,6 +118,7 @@ export const IonBackdrop = /*@__PURE__*/ defineContainer<JSX.IonBackdrop>('ion-b
export const IonBadge = /*@__PURE__*/ defineContainer<JSX.IonBadge>('ion-badge', defineIonBadge, [ export const IonBadge = /*@__PURE__*/ defineContainer<JSX.IonBadge>('ion-badge', defineIonBadge, [
'color', 'color',
'shape',
'size' 'size'
]); ]);