Skip to content

Commit 3dea405

Browse files
authored
feat(badge): design enhancement (#1889)
1 parent be861fa commit 3dea405

File tree

11 files changed

+181
-45
lines changed

11 files changed

+181
-45
lines changed

src/components/badge/badge.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,27 @@ describe('Badge', () => {
7272
`<igc-badge shape="rounded" variant="primary"></igc-badge>`
7373
);
7474
});
75+
76+
it('can be a dot badge', async () => {
77+
const el = await fixture<IgcBadgeComponent>(
78+
html`<igc-badge dot></igc-badge>`
79+
);
80+
81+
expect(el.dot).to.be.true;
82+
83+
el.dot = false;
84+
await elementUpdated(el);
85+
expect(el).dom.to.equal(
86+
`<igc-badge shape="rounded" variant="primary"></igc-badge>`
87+
);
88+
});
89+
90+
it('dot badge works with all variants', async () => {
91+
const el = await fixture<IgcBadgeComponent>(
92+
html`<igc-badge dot variant="success"></igc-badge>`
93+
);
94+
95+
expect(el.dot).to.be.true;
96+
expect(el.variant).to.equal('success');
97+
});
7598
});

src/components/badge/badge.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { html, LitElement, type PropertyValues } from 'lit';
22
import { property } from 'lit/decorators.js';
33
import { addThemingController } from '../../theming/theming-controller.js';
44
import { addInternalsController } from '../common/controllers/internals.js';
5+
import { addSlotController } from '../common/controllers/slot.js';
56
import { registerComponent } from '../common/definitions/register.js';
7+
import { partMap } from '../common/part-map.js';
68
import type { BadgeShape, StyleVariant } from '../types.js';
79
import { styles } from './themes/badge.base.css.js';
810
import { styles as shared } from './themes/shared/badge.common.css.js';
@@ -27,6 +29,21 @@ export default class IgcBadgeComponent extends LitElement {
2729
registerComponent(IgcBadgeComponent);
2830
}
2931

32+
private _iconPart = false;
33+
34+
private readonly _slots = addSlotController(this, {
35+
onChange: this._handleSlotChange,
36+
});
37+
38+
protected _handleSlotChange(): void {
39+
const assignedNodes = this._slots.getAssignedNodes('[default]', true);
40+
this._iconPart = assignedNodes.some(
41+
(node) =>
42+
node.nodeType === Node.ELEMENT_NODE &&
43+
(node as Element).tagName.toLowerCase() === 'igc-icon'
44+
);
45+
}
46+
3047
private readonly _internals = addInternalsController(this, {
3148
initialARIA: { role: 'status' },
3249
});
@@ -52,6 +69,13 @@ export default class IgcBadgeComponent extends LitElement {
5269
@property({ reflect: true })
5370
public shape: BadgeShape = 'rounded';
5471

72+
/**
73+
* Sets whether to render a dot type badge.
74+
* @attr
75+
*/
76+
@property({ type: Boolean, reflect: true })
77+
public dot = false;
78+
5579
constructor() {
5680
super();
5781
addThemingController(this, all);
@@ -65,7 +89,7 @@ export default class IgcBadgeComponent extends LitElement {
6589

6690
protected override render() {
6791
return html`
68-
<span part="base">
92+
<span part=${partMap({ base: true, icon: this._iconPart })}>
6993
<slot></slot>
7094
</span>
7195
`;

src/components/badge/themes/badge.base.scss

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,56 @@
22
@use 'styles/utilities' as *;
33

44
:host {
5-
--size: #{rem(22px)};
6-
--_badge-size: var(--size);
7-
85
width: fit-content;
96
height: fit-content;
107
display: inline-flex;
11-
font-weight: 500;
128
vertical-align: top;
139
}
1410

15-
[part='base'] {
16-
@include type-style('caption');
17-
11+
[part~='base'] {
1812
display: inline-flex;
19-
min-width: var(--size);
20-
min-height: var(--size);
13+
min-width: var(--_badge-size);
14+
min-height: var(--_badge-size);
2115
justify-content: center;
2216
align-items: center;
2317
overflow: hidden;
2418
white-space: nowrap;
19+
font-size: sizable(var(--ig-caption-font-size), var(--ig-body-2-font-size), var(--ig-body-2-font-size));
20+
font-weight: sizable(var(--ig-caption-font-weight), var(--ig-body-2-font-weight), var(--ig-body-2-font-weight));
21+
line-height: sizable(var(--ig-caption-line-height), var(--ig-body-2-line-height), var(--ig-body-2-line-height));
22+
letter-spacing: sizable(var(--ig-caption-letter-spacing), var(--ig-body-2-letter-spacing), var(--ig-body-2-letter-spacing));
23+
text-transform: sizable(var(--ig-caption-text-transform), var(--ig-body-2-text-transform), var(--ig-body-2-text-transform));
2524
}
2625

27-
::slotted(*) {
28-
--size: calc(var(--_badge-size) / 2) !important;
26+
:host(:not(:empty, [dot])) [part='base'] {
27+
padding-inline: pad-inline(rem(4px), rem(6px), rem(8px));
2928
}
3029

31-
:host(:not(:empty)) [part='base'] {
32-
padding-inline: rem(4px);
33-
}
34-
35-
:host([variant='info']) [part='base'] {
30+
:host([variant='info']) [part~='base'] {
3631
background: color(info, 500);
3732
}
3833

39-
:host([variant='success']) [part='base'] {
34+
:host([variant='success']) [part~='base'] {
4035
background: color(success, 500);
4136
}
4237

43-
:host([variant='warning']) [part='base'] {
38+
:host([variant='warning']) [part~='base'] {
4439
background: color(warn, 500);
40+
color: contrast-color(warn, 500);
41+
42+
igc-icon,
43+
::slotted(igc-icon) {
44+
color: contrast-color(warn, 500);
45+
}
4546
}
4647

47-
:host([variant='danger']) [part='base'] {
48+
:host([variant='danger']) [part~='base'] {
4849
background: color(error, 500);
50+
color: contrast-color(error, 900);
4951
}
5052

5153
:host([shape='rounded']),
52-
:host([shape='rounded']) [part='base'] {
53-
border-radius: calc(var(--size) * 2);
54+
:host([shape='rounded']) [part~='base'],
55+
:host([dot]) [part~='base'] {
56+
border-radius: calc(var(--_badge-size) * 2);
5457
}

src/components/badge/themes/dark/badge.indigo.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ $theme: $indigo;
77
:host {
88
@include css-vars-from-theme(diff(light.$base, $theme), 'ig-badge');
99
}
10+
11+
:host([variant='warning']) [part~='base'] {
12+
color: color(gray, 50);
13+
14+
igc-icon,
15+
::slotted(igc-icon) {
16+
color: color(gray, 50);
17+
}
18+
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
@use 'styles/utilities' as *;
2-
@use '../light/themes' as *;
32

4-
$theme: $bootstrap;
5-
6-
:host([outlined]) [part='base'] {
7-
box-shadow: inset 0 0 0 rem(1px) var-get($theme, 'border-color');
3+
:host([variant='danger']) [part~='base'] {
4+
color: contrast-color(error, 100);
85
}

src/components/badge/themes/shared/badge.common.scss

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,19 @@
33

44
$theme: $material;
55

6-
[part='base'] {
6+
:host {
7+
--component-size: var(--ig-size, #{var-get($theme, 'default-size')});
8+
--badge-size: var(--component-size);
9+
--_badge-size: #{var-get($theme, 'size')};
10+
11+
igc-icon,
12+
::slotted(igc-icon) {
13+
--size: #{sizable(rem(12px), rem(14px), rem(16px))};
14+
--component-size: var(--badge-size);
15+
}
16+
}
17+
18+
[part~='base'] {
719
box-shadow: var-get($theme, 'elevation');
820
color: var-get($theme, 'text-color');
921
}
@@ -12,14 +24,26 @@ $theme: $material;
1224
color: var-get($theme, 'icon-color');
1325
}
1426

15-
:host([variant='primary']) [part='base'] {
27+
:host([variant='primary']) [part~='base'] {
1628
background: var-get($theme, 'background-color');
1729
}
1830

19-
:host([shape='square']) [part='base'] {
31+
:host([shape='square']:not([dot])) [part~='base'] {
2032
border-radius: var-get($theme, 'border-radius');
2133
}
2234

23-
:host([outlined]) [part='base'] {
24-
box-shadow: inset 0 0 0 rem(2px) var-get($theme, 'border-color');
35+
:host([outlined]) [part~='base'] {
36+
box-shadow: 0 0 0 rem(2px) var-get($theme, 'border-color');
2537
}
38+
39+
:host([dot]) [part~='base'] {
40+
--_dot-size: #{var-get($theme, 'dot-size')};
41+
42+
min-width: var(--_dot-size);
43+
min-height: var(--_dot-size);
44+
45+
igc-icon,
46+
> * {
47+
display: none;
48+
}
49+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@use 'styles/utilities' as *;
2+
3+
:host([variant='info']) [part~='base'] {
4+
background: color(info, 700);
5+
}

src/components/badge/themes/shared/badge.indigo.scss

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,36 @@
33

44
$theme: $indigo;
55

6-
[part='base'] {
7-
@include type-style('button');
6+
:host {
7+
--component-size: var(--ig-size, #{var-get($theme, 'default-size')});
8+
--badge-size: var(--component-size);
89

10+
igc-icon,
911
::slotted(igc-icon) {
10-
$icon-size: rem(12px);
12+
--size: #{sizable(rem(8px), rem(10px), rem(12px))};
13+
}
14+
}
15+
16+
:host(:not(:empty, [dot])) [part='base'] {
17+
padding-inline: pad-inline(rem(4px), rem(6px), rem(6px));
18+
}
19+
20+
:host([variant='success']) [part~='base'] {
21+
background: color(success, 700);
22+
}
23+
24+
:host([variant='warning']) [part~='base'] {
25+
color: color(gray, 900);
26+
27+
igc-icon,
28+
::slotted(igc-icon) {
29+
color: color(gray, 900);
30+
}
31+
}
1132

12-
--size: #{$icon-size} !important;
13-
--ig-icon-size: #{$icon-size};
14-
--igx-icon-size: #{$icon-size};
33+
[part~='base'] {
34+
@include type-style('button', false) {
35+
font-size: sizable(rem(9px), rem(10px), var(--ig-button-font-size));
36+
line-height: sizable(rem(12px), rem(14px), var(--ig-button-line-height));
1537
}
1638
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@use 'styles/utilities' as *;
2+
3+
:host([variant='danger']) [part~='base'] {
4+
background: color(error, 700);
5+
}
6+
7+
:host([variant='success']) [part~='base'] {
8+
background: color(success, 900);
9+
}
10+
11+
:host([variant='info']) [part~='base'] {
12+
background: color(info, 800);
13+
}

src/components/badge/themes/themes.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import { styles as materialLight } from './light/badge.material.css.js';
1414
import { styles as shared } from './light/badge.shared.css.js';
1515
// Shared Styles
1616
import { styles as bootstrap } from './shared/badge.bootstrap.css.js';
17+
import { styles as fluent } from './shared/badge.fluent.css.js';
1718
import { styles as indigo } from './shared/badge.indigo.css.js';
19+
import { styles as material } from './shared/badge.material.css.js';
1820

1921
const light = {
2022
shared: css`
@@ -24,10 +26,10 @@ const light = {
2426
${bootstrap} ${bootstrapLight}
2527
`,
2628
material: css`
27-
${materialLight}
29+
${material} ${materialLight}
2830
`,
2931
fluent: css`
30-
${fluentLight}
32+
${fluent} ${fluentLight}
3133
`,
3234
indigo: css`
3335
${indigo} ${indigoLight}
@@ -42,10 +44,10 @@ const dark = {
4244
${bootstrap} ${bootstrapDark}
4345
`,
4446
material: css`
45-
${materialDark}
47+
${material} ${materialDark}
4648
`,
4749
fluent: css`
48-
${fluentDark}
50+
${fluent} ${fluentDark}
4951
`,
5052
indigo: css`
5153
${indigo} ${indigoDark}

0 commit comments

Comments
 (0)