Skip to content

Commit 0cc43ae

Browse files
Merge branch '20.1.x' into mkirkova/fix-16262-20.1.x
2 parents ad45f9e + 2fa91b3 commit 0cc43ae

25 files changed

+439
-124
lines changed

projects/igniteui-angular/src/lib/badge/README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# igx-badge
22

33
The **igx-badge** component is an absolutely positioned element that can be used in tandem with other components such as avatars, navigation menus, or anywhere else in an app where some active indication is required.
4-
With the igx-badge you can display active count or an icon in several different predefined styles.
4+
With the igx-badge you can display active count or an icon in several different predefined styles and sizes.
55
A walkthrough of how to get started can be found [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/badge.html)
66

77
# Usage
@@ -14,9 +14,12 @@ A walkthrough of how to get started can be found [here](https://www.infragistics
1414
|:----------|:-------------:|:------|
1515
| `id` | string | Unique identifier of the component. If not provided it will be automatically generated.|
1616
| `type` | string | Set the type of the badge to either `primary`, `info`, `success`, `warning`, or `error`. This will change the background color of the badge according to the values set in the default theme. |
17+
| `dot` | boolean | Set whether the badge is displayed as a minimal dot indicator without any content. Default is `false`. |
1718
| `position` | string | Set the position of the badge relative to its parent container to either `top-right`, `top-left`, `bottom-right`, or `bottom-left`. |
1819
| `value` | string | Set the value to be displayed inside the badge. |
1920
| `icon` | string | Set an icon for the badge from the material icons set. Will not be displayed if `value` for the badge is already set. |
21+
| `outlined` | boolean | Set whether the badge should have an outline. Default is `false`. |
22+
| `shape` | string | Set the shape of the badge to either `rounded` or `square`. Default is `rounded`. |
2023

2124
# Examples
2225

@@ -26,3 +29,18 @@ Using `igx-badge` with the `igx-avatar` component to show active status.
2629
<igx-badge type="info" value="8"></igx-badge>
2730
</igx-avatar>
2831
```
32+
33+
Using `igx-badge` as a dot indicator for notifications.
34+
```html
35+
<igx-badge dot type="success"></igx-badge>
36+
<igx-badge dot outlined type="error"></igx-badge>
37+
```
38+
39+
Using different badge types.
40+
```html
41+
<igx-badge type="primary" value="1"></igx-badge>
42+
<igx-badge type="info" value="2"></igx-badge>
43+
<igx-badge type="success" value="3"></igx-badge>
44+
<igx-badge type="warning" value="4"></igx-badge>
45+
<igx-badge type="error" value="5"></igx-badge>
46+
```

projects/igniteui-angular/src/lib/badge/badge.component.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ describe('Badge', () => {
1111
InitBadgeWithDefaultsComponent,
1212
InitBadgeWithIconComponent,
1313
IgxBadgeComponent,
14-
InitBadgeWithIconARIAComponent
14+
InitBadgeWithIconARIAComponent,
15+
InitBadgeWithDotComponent
1516
]
1617
}).compileComponents();
1718
}));
@@ -87,6 +88,26 @@ describe('Badge', () => {
8788
const container = fixture.nativeElement.querySelectorAll('.igx-badge')[0];
8889
expect(container.getAttribute('aria-roledescription')).toMatch(expectedDescription);
8990
});
91+
92+
it('Initializes badge with dot property', () => {
93+
const fixture = TestBed.createComponent(InitBadgeWithDotComponent);
94+
fixture.detectChanges();
95+
const badge = fixture.componentInstance.badge;
96+
97+
expect(badge.dot).toBeTruthy();
98+
expect(fixture.debugElement.query(By.css('.igx-badge--dot'))).toBeTruthy();
99+
});
100+
101+
it('Initializes success badge as dot', () => {
102+
const fixture = TestBed.createComponent(InitBadgeWithDotComponent);
103+
fixture.detectChanges();
104+
const badge = fixture.componentInstance.badge;
105+
106+
expect(badge.type).toBe(IgxBadgeType.SUCCESS);
107+
expect(badge.dot).toBeTruthy();
108+
expect(fixture.debugElement.query(By.css('.igx-badge--dot'))).toBeTruthy();
109+
expect(fixture.debugElement.query(By.css('.igx-badge--success'))).toBeTruthy();
110+
});
90111
});
91112

92113
@Component({
@@ -120,3 +141,11 @@ class InitBadgeWithIconComponent {
120141
class InitBadgeWithIconARIAComponent {
121142
@ViewChild(IgxBadgeComponent, { static: true }) public badge: IgxBadgeComponent;
122143
}
144+
145+
@Component({
146+
template: `<igx-badge dot type="success"></igx-badge>`,
147+
imports: [IgxBadgeComponent]
148+
})
149+
class InitBadgeWithDotComponent {
150+
@ViewChild(IgxBadgeComponent, { static: true }) public badge: IgxBadgeComponent;
151+
}

projects/igniteui-angular/src/lib/badge/badge.component.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ export class IgxBadgeComponent {
153153
/** @hidden @internal */
154154
@HostBinding('class.igx-badge--square')
155155
public get _squareShape(): boolean {
156-
return this.shape === 'square';
156+
if (!this.dot) {
157+
return this.shape === 'square';
158+
}
157159
}
158160

159161
/**
@@ -183,6 +185,20 @@ export class IgxBadgeComponent {
183185
@HostBinding('class.igx-badge--outlined')
184186
public outlined = false;
185187

188+
/**
189+
* Sets/gets whether the badge is displayed as a dot.
190+
* When true, the badge will be rendered as a minimal 8px indicator without any content.
191+
* Default value is `false`.
192+
*
193+
* @example
194+
* ```html
195+
* <igx-badge dot type="success"></igx-badge>
196+
* ```
197+
*/
198+
@Input({transform: booleanAttribute})
199+
@HostBinding('class.igx-badge--dot')
200+
public dot = false;
201+
186202
/**
187203
* Defines a human-readable, accessor, author-localized description for
188204
* the `type` and the `icon` or `value` of the element.

projects/igniteui-angular/src/lib/calendar/calendar.component.html

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,25 @@ <h2 id="igx-aria-calendar-title-month" class="igx-calendar__header-date">
192192
(focus)="this.onWrapperFocus($event)"
193193
(blur)="this.onWrapperBlur($event)"
194194
>
195-
<caption id="calendar-desc" tabindex="-1" class="igx-calendar__aria-off-screen">
196-
@if (selection === 'multi') {
197-
{{ monthsViewNumber && monthsViewNumber > 1 ?
198-
resourceStrings.igx_calendar_multi_selection.replace('{0}', monthsViewNumber.toString()) :
199-
resourceStrings.igx_calendar_singular_multi_selection}}
200-
}
201-
@if (selection === 'range') {
202-
{{ monthsViewNumber && monthsViewNumber > 1 ?
203-
resourceStrings.igx_calendar_range_selection.replace('{0}', monthsViewNumber.toString()) :
204-
resourceStrings.igx_calendar_singular_range_selection}}
205-
}
206-
@if (selection === 'single') {
207-
{{ monthsViewNumber && monthsViewNumber > 1 ?
208-
resourceStrings.igx_calendar_single_selection.replace('{0}', monthsViewNumber.toString()) :
209-
resourceStrings.igx_calendar_singular_single_selection}}
195+
<div id="calendar-desc" tabindex="-1" class="igx-calendar__aria-off-screen">
196+
@switch (selection) {
197+
@case ('multi') {
198+
{{ monthsViewNumber && monthsViewNumber > 1 ?
199+
resourceStrings.igx_calendar_multi_selection.replace('{0}', monthsViewNumber.toString()) :
200+
resourceStrings.igx_calendar_singular_multi_selection}}
201+
}
202+
@case ('range') {
203+
{{ monthsViewNumber && monthsViewNumber > 1 ?
204+
resourceStrings.igx_calendar_range_selection.replace('{0}', monthsViewNumber.toString()) :
205+
resourceStrings.igx_calendar_singular_range_selection}}
206+
}
207+
@default {
208+
{{ monthsViewNumber && monthsViewNumber > 1 ?
209+
resourceStrings.igx_calendar_single_selection.replace('{0}', monthsViewNumber.toString()) :
210+
resourceStrings.igx_calendar_singular_single_selection}}
211+
}
210212
}
211-
</caption>
213+
</div>
212214
<section
213215
class="igx-calendar__pickers"
214216
[class.igx-calendar__pickers--days]="isDefaultView"

projects/igniteui-angular/src/lib/calendar/calendar.component.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,9 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
439439
@HostListener('mousedown', ['$event'])
440440
protected onMouseDown(event: MouseEvent) {
441441
event.stopPropagation();
442-
this.wrapper.nativeElement.focus();
442+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
443+
this.wrapper.nativeElement.focus();
444+
}
443445
}
444446

445447
private _showActiveDay: boolean;
@@ -841,7 +843,9 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
841843

842844
if (this.platform.isActivationKey(event)) {
843845
this.viewDate = date;
844-
this.wrapper.nativeElement.focus();
846+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
847+
this.wrapper.nativeElement.focus();
848+
}
845849
}
846850
}
847851

@@ -850,6 +854,10 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
850854
* @internal
851855
*/
852856
public onYearsViewClick(event: MouseEvent) {
857+
if (!this.platform.isBrowser) {
858+
return;
859+
}
860+
853861
const path = event.composed ? event.composedPath() : [event.target];
854862
const years = this.dacadeView.viewItems.toArray();
855863
const validTarget = years.some(year => path.includes(year.nativeElement));
@@ -997,7 +1005,9 @@ export class IgxCalendarComponent extends IgxCalendarBaseDirective implements Af
9971005
this.activeViewIdx = activeViewIdx;
9981006
this.viewDate = date;
9991007

1000-
this.wrapper.nativeElement.focus();
1008+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
1009+
this.wrapper.nativeElement.focus();
1010+
}
10011011
}
10021012
}
10031013

projects/igniteui-angular/src/lib/calendar/calendar.services.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
import { Injectable, ElementRef, NgZone } from "@angular/core";
1+
import { Injectable, ElementRef, NgZone, inject } from "@angular/core";
22
import { EventManager } from "@angular/platform-browser";
3+
import { PlatformUtil } from "../core/utils";
34

45
@Injectable()
56
export class KeyboardNavigationService {
67
private keyHandlers = new Map<string, (event: KeyboardEvent) => void>();
78
private eventUnsubscribeFn: Function | null = null;
9+
private platform = inject(PlatformUtil);
810

911
constructor(
1012
private eventManager: EventManager,
1113
private ngZone: NgZone,
1214
) {}
1315

1416
public attachKeyboardHandlers(elementRef: ElementRef, context: any) {
17+
if (!this.platform.isBrowser) {
18+
return this;
19+
}
20+
1521
this.detachKeyboardHandlers(); // Clean up any existing listeners
1622

1723
this.ngZone.runOutsideAngular(() => {

projects/igniteui-angular/src/lib/calendar/days-view/days-view.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ export class IgxDaysViewComponent extends IgxCalendarBaseDirective {
349349
});
350350
}
351351

352-
if (this.tabIndex !== -1) {
352+
if (this.tabIndex !== -1 && this.platform.isBrowser && this.el?.nativeElement) {
353353
this.el.nativeElement.focus();
354354
}
355355

projects/igniteui-angular/src/lib/calendar/month-picker/month-picker.component.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ export class IgxMonthPickerComponent extends IgxCalendarBaseDirective implements
152152

153153
if (this.platform.isActivationKey(event)) {
154154
this.viewDate = date;
155-
this.wrapper.nativeElement.focus();
155+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
156+
this.wrapper.nativeElement.focus();
157+
}
156158
}
157159
}
158160

@@ -188,9 +190,13 @@ export class IgxMonthPickerComponent extends IgxCalendarBaseDirective implements
188190
public override activeViewDecade() {
189191
super.activeViewDecade();
190192

191-
requestAnimationFrame(() => {
192-
this.dacadeView.el.nativeElement.focus();
193-
});
193+
if (this.platform.isBrowser) {
194+
requestAnimationFrame(() => {
195+
if (this.dacadeView?.el?.nativeElement) {
196+
this.dacadeView.el.nativeElement.focus();
197+
}
198+
});
199+
}
194200
}
195201

196202
/**
@@ -221,7 +227,9 @@ export class IgxMonthPickerComponent extends IgxCalendarBaseDirective implements
221227
);
222228

223229
this.activeView = IgxCalendarView.Year;
224-
this.wrapper.nativeElement.focus();
230+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
231+
this.wrapper.nativeElement.focus();
232+
}
225233
}
226234

227235
/**
@@ -279,7 +287,9 @@ export class IgxMonthPickerComponent extends IgxCalendarBaseDirective implements
279287
@HostListener('mousedown', ['$event'])
280288
protected onMouseDown(event: MouseEvent) {
281289
event.stopPropagation();
282-
this.wrapper.nativeElement.focus();
290+
if (this.platform.isBrowser && this.wrapper?.nativeElement) {
291+
this.wrapper.nativeElement.focus();
292+
}
283293
}
284294

285295
private _showActiveDay: boolean;

projects/igniteui-angular/src/lib/calendar/months-view/months-view.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ElementRef,
66
booleanAttribute,
77
Inject,
8+
inject,
89
} from "@angular/core";
910
import { IgxCalendarMonthDirective } from "../calendar.directives";
1011
import { TitleCasePipe } from "@angular/common";
@@ -16,6 +17,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
1617
import { CalendarDay } from "../common/model";
1718
import type { DayInterval } from "../common/model";
1819
import { calendarRange } from "../common/helpers";
20+
import { PlatformUtil } from "../../core/utils";
1921

2022
let NEXT_ID = 0;
2123

@@ -37,6 +39,7 @@ let NEXT_ID = 0;
3739
})
3840
export class IgxMonthsViewComponent extends IgxCalendarViewDirective implements ControlValueAccessor {
3941
#standalone = true;
42+
private platform = inject(PlatformUtil);
4043

4144
/**
4245
* Sets/gets the `id` of the months view.
@@ -139,7 +142,7 @@ export class IgxMonthsViewComponent extends IgxCalendarViewDirective implements
139142
* @hidden
140143
*/
141144
protected onMouseDown() {
142-
if (this.tabIndex !== -1) {
145+
if (this.tabIndex !== -1 && this.platform.isBrowser && this.el?.nativeElement) {
143146
this.el.nativeElement.focus();
144147
}
145148
}

projects/igniteui-angular/src/lib/calendar/years-view/years-view.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
HostBinding,
55
ElementRef,
66
Inject,
7+
inject,
78
} from "@angular/core";
89
import { IgxCalendarYearDirective } from "../calendar.directives";
910
import {
@@ -14,6 +15,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
1415
import { CalendarDay } from "../common/model";
1516
import type { DayInterval } from "../common/model";
1617
import { calendarRange } from "../common/helpers";
18+
import { PlatformUtil } from "../../core/utils";
1719

1820
@Component({
1921
providers: [
@@ -33,6 +35,7 @@ import { calendarRange } from "../common/helpers";
3335
})
3436
export class IgxYearsViewComponent extends IgxCalendarViewDirective implements ControlValueAccessor {
3537
#standalone = true;
38+
private platform = inject(PlatformUtil);
3639

3740
/**
3841
* The default css class applied to the component.
@@ -158,7 +161,7 @@ export class IgxYearsViewComponent extends IgxCalendarViewDirective implements C
158161
* @hidden
159162
*/
160163
protected onMouseDown() {
161-
if (this.tabIndex !== -1) {
164+
if (this.tabIndex !== -1 && this.platform.isBrowser && this.el?.nativeElement) {
162165
this.el.nativeElement.focus();
163166
}
164167
}

0 commit comments

Comments
 (0)