fix(button): update styling for badge (#30414)
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 current behavior? Some stylings for the ion-badge when slotted in an ion-button were missing. ## What is the new behavior? Updated the styling for the ion-badge when slotted in an ion-button according to the designs: - Adjusted badge padding; - Abandoned the `:has` pseudo-selector for a simple 'button-had-badge' class; - Adjusted font-size for icons inside the button; - Adjusted badge positioning according to button size and badge length. ## 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. -->
@ -160,17 +160,12 @@
|
||||
// Badge in Button
|
||||
// --------------------------------------------------
|
||||
|
||||
:host([vertical]:not(.in-tab-button).in-button.badge-small) {
|
||||
@include globals.position(null, calc(-1 * var(globals.$ion-space-050)));
|
||||
}
|
||||
|
||||
:host([vertical]:not(.in-tab-button).in-button.badge-medium),
|
||||
:host([vertical]:not(.in-tab-button).in-button.badge-large) {
|
||||
@include globals.position(null, globals.$ion-space-050);
|
||||
}
|
||||
|
||||
:host(:not(:empty).in-button) {
|
||||
--padding-start: #{globals.$ion-scale-050};
|
||||
--padding-end: #{globals.$ion-scale-050};
|
||||
|
||||
@include globals.typography(globals.$ion-body-action-xs);
|
||||
|
||||
min-width: globals.$ion-scale-400;
|
||||
height: globals.$ion-scale-400;
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ export class Badge implements ComponentInterface {
|
||||
const theme = getIonTheme(this);
|
||||
const { size } = this;
|
||||
|
||||
// TODO(ROU-10747): Remove theme check when sizes are defined for all themes.
|
||||
// TODO(FW-6355): Remove theme check when sizes are defined for all themes.
|
||||
if (theme !== 'ionic') {
|
||||
return undefined;
|
||||
}
|
||||
@ -133,6 +133,7 @@ export class Badge implements ComponentInterface {
|
||||
[`badge-vertical-${this.vertical}`]: this.vertical !== undefined,
|
||||
'in-button': hostContext('ion-button', this.el),
|
||||
'in-tab-button': hostContext('ion-tab-button', this.el),
|
||||
'long-badge': (this.el.textContent?.trim().length ?? 0) > 2,
|
||||
})}
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
@ -56,5 +56,13 @@ configs({ directions: ['ltr'], modes: ['md', 'ios', 'ionic-md'] }).forEach(({ co
|
||||
|
||||
await expect(container).toHaveScreenshot(screenshot(`badge-hint-button-bottom`));
|
||||
});
|
||||
|
||||
test('should not have visual regressions for different button sizes', async ({ page }) => {
|
||||
await page.goto('/src/components/badge/test/hint', config);
|
||||
|
||||
const container = page.locator('#button-size');
|
||||
|
||||
await expect(container).toHaveScreenshot(screenshot(`badge-hint-button-size`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
@ -417,6 +417,47 @@
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-list>
|
||||
<ion-list id="button-size">
|
||||
<ion-list-header>
|
||||
<ion-label> Inside Button - Button Size </ion-label>
|
||||
</ion-list-header>
|
||||
<div class="ion-display-flex ion-align-items-center ion-justify-content-around ion-margin">
|
||||
<ion-button fill="clear">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="top">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="small">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="top">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="medium">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="top">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="large">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="top">1</ion-badge>
|
||||
</ion-button>
|
||||
</div>
|
||||
<div class="ion-display-flex ion-align-items-center ion-justify-content-around ion-margin">
|
||||
<ion-button fill="clear">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="bottom">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="small">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="bottom">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="medium">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="bottom">1</ion-badge>
|
||||
</ion-button>
|
||||
<ion-button fill="clear" size="large">
|
||||
<ion-icon slot="icon-only" name="add"></ion-icon>
|
||||
<ion-badge color="danger" size="small" vertical="bottom">1</ion-badge>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
@ -304,13 +304,7 @@ ion-ripple-effect {
|
||||
@include border-radius(inherit);
|
||||
}
|
||||
|
||||
// This rule works for Chrome.
|
||||
:has(ion-badge) .button-native {
|
||||
--overflow: visible;
|
||||
}
|
||||
|
||||
// This rule works for the rest of the browsers.
|
||||
:host(:has(ion-badge)) .button-native {
|
||||
:host(.button-has-badge) .button-native {
|
||||
--overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
@ -131,15 +131,14 @@
|
||||
::slotted(ion-icon[slot="start"]),
|
||||
::slotted(ion-icon[slot="end"]),
|
||||
::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: globals.$ion-font-size-400;
|
||||
font-size: globals.$ion-font-size-500;
|
||||
}
|
||||
|
||||
:host(.button-small),
|
||||
:host(.button-large) {
|
||||
::slotted(ion-icon[slot="start"]),
|
||||
::slotted(ion-icon[slot="end"]),
|
||||
::slotted(ion-icon[slot="icon-only"]) {
|
||||
font-size: inherit;
|
||||
font-size: globals.$ion-font-size-600;
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,8 +263,46 @@
|
||||
@include globals.margin-horizontal(globals.$ion-space-300, null);
|
||||
}
|
||||
|
||||
// Button Badge
|
||||
// Button with Badge
|
||||
// --------------------------------------------------
|
||||
:host ::slotted(ion-badge[vertical]:not(:empty)) {
|
||||
@include globals.padding(globals.$ion-space-050);
|
||||
|
||||
:host(.button-has-badge) {
|
||||
--padding-top: #{globals.$ion-space-0};
|
||||
--padding-bottom: #{globals.$ion-space-0};
|
||||
}
|
||||
|
||||
:host(.button-small) ::slotted(ion-badge) {
|
||||
@include globals.position(null, calc(-1 * globals.$ion-space-050), null, null);
|
||||
}
|
||||
|
||||
:host(.button-medium) {
|
||||
::slotted(ion-badge.long-badge.badge-vertical-top) {
|
||||
@include globals.position($top: globals.$ion-space-100);
|
||||
}
|
||||
::slotted(ion-badge.long-badge.badge-vertical-bottom) {
|
||||
@include globals.position($bottom: globals.$ion-space-100);
|
||||
}
|
||||
|
||||
::slotted(ion-badge:not(.long-badge).badge-vertical-top) {
|
||||
@include globals.position(globals.$ion-space-100, globals.$ion-space-150, null, null);
|
||||
}
|
||||
::slotted(ion-badge:not(.long-badge).badge-vertical-bottom) {
|
||||
@include globals.position(null, globals.$ion-space-150, globals.$ion-space-100, null);
|
||||
}
|
||||
}
|
||||
|
||||
:host(.button-large) {
|
||||
::slotted(ion-badge.long-badge.badge-vertical-top) {
|
||||
@include globals.position($top: globals.$ion-space-200);
|
||||
}
|
||||
::slotted(ion-badge.long-badge.badge-vertical-bottom) {
|
||||
@include globals.position($bottom: globals.$ion-space-200);
|
||||
}
|
||||
|
||||
::slotted(ion-badge:not(.long-badge).badge-vertical-top) {
|
||||
@include globals.position(globals.$ion-space-200, globals.$ion-space-200, null, null);
|
||||
}
|
||||
::slotted(ion-badge:not(.long-badge).badge-vertical-bottom) {
|
||||
@include globals.position(null, globals.$ion-space-200, globals.$ion-space-200, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,6 +206,10 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
return !!this.el.querySelector('[slot="icon-only"]');
|
||||
}
|
||||
|
||||
private get hasBadge() {
|
||||
return !!this.el.querySelector('ion-badge');
|
||||
}
|
||||
|
||||
private get rippleType() {
|
||||
const hasClearFill = this.fill === undefined || this.fill === 'clear';
|
||||
|
||||
@ -345,8 +349,20 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
};
|
||||
|
||||
render() {
|
||||
const { buttonType, type, disabled, rel, target, href, color, expand, hasIconOnly, strong, inheritedAttributes } =
|
||||
this;
|
||||
const {
|
||||
buttonType,
|
||||
type,
|
||||
disabled,
|
||||
rel,
|
||||
target,
|
||||
href,
|
||||
color,
|
||||
expand,
|
||||
hasIconOnly,
|
||||
hasBadge,
|
||||
strong,
|
||||
inheritedAttributes,
|
||||
} = this;
|
||||
|
||||
const theme = getIonTheme(this);
|
||||
const mode = getIonMode(this);
|
||||
@ -398,6 +414,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
||||
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
|
||||
'in-buttons': hostContext('ion-buttons', this.el),
|
||||
'button-has-icon-only': hasIconOnly,
|
||||
'button-has-badge': hasBadge,
|
||||
'button-disabled': disabled,
|
||||
'ion-activatable': true,
|
||||
'ion-focusable': true,
|
||||
|
||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |