Skip to content

Commit 22f4ded

Browse files
committed
Release 10.0.0
1 parent fe63f1d commit 22f4ded

40 files changed

Lines changed: 614 additions & 365 deletions

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## 10.0.0 (23.02.2026)
2+
3+
This version requires Angular v21. Follow the [Angular Update Guide](https://angular.dev/update-guide) to migrate your project to Angular 21.
4+
5+
### Breaking changes:
6+
7+
- Updated Angular to v21, this version is required in MDB Angular v10
8+
9+
### Fixes and improvements:
10+
11+
- Improved components change detection to ensure support for Zoneless applications
12+
- [Sidenav](https://mdbootstrap.com/docs/angular/navigation/sidenav/) - fixed behavior of `slim` and `slimCollapsed` inputs
13+
14+
---
15+
116
## 9.1.0 (15.12.2025)
217

318
### Fixes and improvements:

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Bootstrap 5 & Angular 20 UI KIT - 700+ components, MIT license, simple installation.
1+
Bootstrap 5 & Angular 21 UI KIT - 700+ components, MIT license, simple installation.
22

33
MDB is a collection of free Bootstrap templates, themes, design tools & resources.
44

@@ -17,7 +17,7 @@ One click setup! MDB GO allows you to create a WordPress page with a single clic
1717
Regardless whether you want to create a Travel Blog or an e-commerce shop to sell your product you can easily do that. You can even combine both into single page.
1818

1919

20-
## About Material Design for Bootstrap 5 & Angular 20
20+
## About Material Design for Bootstrap 5 & Angular 21
2121

2222
<p>Created by <a href="https://mdbootstrap.com"><img height="30" src="https://mdbootstrap.com/img/Marketing/general/logo/medium/mdb-angular-r.png"></a>
2323
<a href="https://npmcharts.com/compare/angular-bootstrap-md?minimal=true"> <img src="https://img.shields.io/npm/dm/mdbootstrap.svg?label=NPM%20Downloads" alt="Downloads"></a>

README.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MDB 5 Angular
22

3-
Version: FREE 9.1.0
3+
Version: FREE 10.0.0
44

55
Documentation:
66
https://mdbootstrap.com/docs/angular/

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mdb-angular-ui-kit-free",
3-
"version": "9.1.0",
3+
"version": "10.0.0",
44
"scripts": {
55
"ng": "ng",
66
"start": "ng serve",

projects/mdb-angular-ui-kit/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## 10.0.0 (23.02.2026)
2+
3+
This version requires Angular v21. Follow the [Angular Update Guide](https://angular.dev/update-guide) to migrate your project to Angular 21.
4+
5+
### Breaking changes:
6+
7+
- Updated Angular to v21, this version is required in MDB Angular v10
8+
9+
### Fixes and improvements:
10+
11+
- Improved components change detection to ensure support for Zoneless applications
12+
- [Sidenav](https://mdbootstrap.com/docs/angular/navigation/sidenav/) - fixed behavior of `slim` and `slimCollapsed` inputs
13+
14+
---
15+
116
## 9.1.0 (15.12.2025)
217

318
### Fixes and improvements:

projects/mdb-angular-ui-kit/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Bootstrap 5 & Angular 20 UI KIT - 700+ components, MIT license, simple installation.
1+
Bootstrap 5 & Angular 21 UI KIT - 700+ components, MIT license, simple installation.
22

33
MDB is a collection of free Bootstrap templates, themes, design tools & resources.
44

@@ -17,7 +17,7 @@ One click setup! MDB GO allows you to create a WordPress page with a single clic
1717
Regardless whether you want to create a Travel Blog or an e-commerce shop to sell your product you can easily do that. You can even combine both into single page.
1818

1919

20-
## About Material Design for Bootstrap 5 & Angular 20
20+
## About Material Design for Bootstrap 5 & Angular 21
2121

2222
<p>Created by <a href="https://mdbootstrap.com"><img height="30" src="https://mdbootstrap.com/img/Marketing/general/logo/medium/mdb-angular-r.png"></a>
2323
<a href="https://npmcharts.com/compare/angular-bootstrap-md?minimal=true"> <img src="https://img.shields.io/npm/dm/mdbootstrap.svg?label=NPM%20Downloads" alt="Downloads"></a>

projects/mdb-angular-ui-kit/accordion/accordion-item.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h2 class="accordion-header" [id]="_headerId">
1010
>
1111
{{ header }}
1212
@if (_headerTemplate) {
13-
<ng-template [ngTemplateOutlet]="_headerTemplate"></ng-template>
13+
<ng-template [ngTemplateOutlet]="_headerTemplate"></ng-template>
1414
}
1515
</button>
1616
</h2>
@@ -25,7 +25,7 @@ <h2 class="accordion-header" [id]="_headerId">
2525
>
2626
<div class="accordion-body">
2727
@if (_bodyTemplate) {
28-
<ng-template [ngTemplateOutlet]="_bodyTemplate"></ng-template>
28+
<ng-template [ngTemplateOutlet]="_bodyTemplate"></ng-template>
2929
}
3030
</div>
3131
</div>

projects/mdb-angular-ui-kit/accordion/accordion.spec.ts

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { Component, QueryList, ViewChildren } from '@angular/core';
2-
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
2+
import { ComponentFixture, TestBed } from '@angular/core/testing';
3+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
34
import { MdbAccordionItemComponent } from './accordion-item.component';
45
import { MdbAccordionModule } from './accordion.module';
56

6-
const ANIMATION_TIME = 350; // animation time from collapse directive
7-
87
const template = `
98
<mdb-accordion [multiple]="multiple" [flush]="flush" [borderless]="borderless">
109
<mdb-accordion-item [disabled]="disabled">
@@ -67,10 +66,15 @@ describe('MDB Accordion', () => {
6766
let element: any;
6867
let component: any;
6968

69+
// Helper to dispatch transitionend event (jsdom doesn't fire CSS transitions)
70+
const dispatchTransitionEnd = (el: HTMLElement) => {
71+
el.dispatchEvent(new Event('transitionend'));
72+
};
73+
7074
beforeEach(() => {
7175
TestBed.configureTestingModule({
7276
declarations: [TestAccordionComponent],
73-
imports: [MdbAccordionModule],
77+
imports: [MdbAccordionModule, NoopAnimationsModule],
7478
teardown: { destroyAfterEach: false },
7579
});
7680
fixture = TestBed.createComponent(TestAccordionComponent);
@@ -79,95 +83,112 @@ describe('MDB Accordion', () => {
7983
element = fixture.nativeElement;
8084
});
8185

82-
it('should toggle item on click', fakeAsync(() => {
86+
it('should toggle item on click', async () => {
8387
const item = document.querySelector('.accordion-item') as HTMLElement;
8488
const button = item.querySelector('.accordion-button') as HTMLElement;
89+
const collapseEl = item.querySelector('.collapse') as HTMLElement;
8590

8691
button.click();
8792
fixture.detectChanges();
88-
flush();
89-
90-
const itemCollapse = item.querySelector('.collapse');
93+
dispatchTransitionEnd(collapseEl);
94+
await fixture.whenStable();
95+
fixture.detectChanges();
9196

9297
expect(button.classList).not.toContain('collapsed');
93-
expect(itemCollapse.classList).toContain('show');
98+
expect(collapseEl.classList).toContain('show');
9499

95100
button.click();
96101
fixture.detectChanges();
97-
flush();
102+
dispatchTransitionEnd(collapseEl);
103+
await fixture.whenStable();
104+
fixture.detectChanges();
98105

99106
expect(button.classList).toContain('collapsed');
100-
expect(itemCollapse.classList).not.toContain('show');
101-
}));
107+
expect(collapseEl.classList).not.toContain('show');
108+
});
102109

103-
it('should toggle item when toggle method is used', fakeAsync(() => {
110+
it('should toggle item when toggle method is used', async () => {
104111
const item = document.querySelector('.accordion-item') as HTMLElement;
105112
const button = item.querySelector('.accordion-button') as HTMLElement;
106-
component.accordionItems[0].toggle();
113+
const collapseEl = item.querySelector('.collapse') as HTMLElement;
107114

115+
component.accordionItems[0].toggle();
116+
fixture.detectChanges();
117+
dispatchTransitionEnd(collapseEl);
118+
await fixture.whenStable();
108119
fixture.detectChanges();
109-
flush();
110-
111-
const itemCollapse = item.querySelector('.collapse');
112120

113121
expect(button.classList).not.toContain('collapsed');
114-
expect(itemCollapse.classList).toContain('show');
122+
expect(collapseEl.classList).toContain('show');
115123

116124
component.accordionItems[0].toggle();
117125
fixture.detectChanges();
118-
flush();
126+
dispatchTransitionEnd(collapseEl);
127+
await fixture.whenStable();
128+
fixture.detectChanges();
119129

120130
expect(button.classList).toContain('collapsed');
121-
expect(itemCollapse.classList).not.toContain('show');
122-
}));
131+
expect(collapseEl.classList).not.toContain('show');
132+
});
123133

124-
it('should allow only one item to be opened if multiple is set to false', fakeAsync(() => {
134+
it('should allow only one item to be opened if multiple is set to false', async () => {
125135
const buttons = document.querySelectorAll('.accordion-button');
126136
const contents = document.querySelectorAll('.collapse');
127137

128138
component.accordionItems[0].toggle();
129139
fixture.detectChanges();
130-
flush();
140+
dispatchTransitionEnd(contents[0] as HTMLElement);
141+
await fixture.whenStable();
142+
fixture.detectChanges();
131143

132144
expect(buttons[0].classList).not.toContain('collapsed');
133145
expect(contents[0].classList).toContain('show');
134146

135147
component.accordionItems[1].toggle();
136148
fixture.detectChanges();
137-
flush();
149+
dispatchTransitionEnd(contents[0] as HTMLElement); // first item closing
150+
dispatchTransitionEnd(contents[1] as HTMLElement); // second item opening
151+
await fixture.whenStable();
152+
fixture.detectChanges();
138153

139154
expect(buttons[0].classList).toContain('collapsed');
140155
expect(contents[0].classList).not.toContain('show');
141156
expect(buttons[1].classList).not.toContain('collapsed');
142157
expect(contents[1].classList).toContain('show');
143-
}));
158+
});
144159

145-
it('should allow multiple items to be opened if multiple is set to true', fakeAsync(() => {
160+
it('should allow multiple items to be opened if multiple is set to true', async () => {
146161
component.multiple = true;
162+
fixture.changeDetectorRef.markForCheck();
147163
fixture.detectChanges();
148164

149165
const buttons = document.querySelectorAll('.accordion-button');
150166
const contents = document.querySelectorAll('.collapse');
151167

152168
component.accordionItems[0].toggle();
153169
fixture.detectChanges();
154-
flush();
170+
dispatchTransitionEnd(contents[0] as HTMLElement);
171+
await fixture.whenStable();
172+
fixture.detectChanges();
155173

156174
expect(buttons[0].classList).not.toContain('collapsed');
157175
expect(contents[0].classList).toContain('show');
158176

159177
component.accordionItems[1].toggle();
160178
fixture.detectChanges();
161-
flush();
179+
dispatchTransitionEnd(contents[1] as HTMLElement);
180+
await fixture.whenStable();
181+
fixture.detectChanges();
162182

163183
expect(buttons[0].classList).not.toContain('collapsed');
164184
expect(contents[0].classList).toContain('show');
165185
expect(buttons[1].classList).not.toContain('collapsed');
166186
expect(contents[1].classList).toContain('show');
167-
}));
187+
});
168188

169189
it('should add accordion-flush class if flush is set to true', () => {
170190
component.flush = true;
191+
fixture.changeDetectorRef.markForCheck();
171192
fixture.detectChanges();
172193

173194
const accordion = document.querySelector('.accordion');
@@ -181,13 +202,15 @@ describe('MDB Accordion', () => {
181202
expect(accordion.classList).not.toContain('accordion-borderless');
182203

183204
component.borderless = true;
205+
fixture.changeDetectorRef.markForCheck();
184206
fixture.detectChanges();
185207

186208
expect(accordion.classList).toContain('accordion-borderless');
187209
});
188210

189-
it('should emit correct events on item collapse and expand', fakeAsync(() => {
211+
it('should emit correct events on item collapse and expand', async () => {
190212
const item = component.accordionItems[0];
213+
const content = document.querySelectorAll('.collapse')[0] as HTMLElement;
191214

192215
const showSpy = jest.spyOn(item.itemShow, 'emit');
193216
const shownSpy = jest.spyOn(item.itemShown, 'emit');
@@ -196,31 +219,30 @@ describe('MDB Accordion', () => {
196219

197220
item.show();
198221
fixture.detectChanges();
199-
200-
expect(showSpy).toHaveBeenCalled();
201-
expect(shownSpy).not.toHaveBeenCalled();
202-
203-
tick(ANIMATION_TIME);
204-
flush();
222+
// First transitionend completes the initial show, which triggers a recursive show() in the setter
223+
dispatchTransitionEnd(content);
224+
await fixture.whenStable();
225+
// Second transitionend completes the recursive show()
226+
dispatchTransitionEnd(content);
227+
await fixture.whenStable();
205228
fixture.detectChanges();
206229

230+
expect(showSpy).toHaveBeenCalled();
207231
expect(shownSpy).toHaveBeenCalled();
208232

209233
item.hide();
210234
fixture.detectChanges();
211-
212-
expect(hideSpy).toHaveBeenCalled();
213-
expect(hiddenSpy).not.toHaveBeenCalled();
214-
215-
tick(ANIMATION_TIME);
216-
flush();
235+
dispatchTransitionEnd(content);
236+
await fixture.whenStable();
217237
fixture.detectChanges();
218238

239+
expect(hideSpy).toHaveBeenCalled();
219240
expect(hiddenSpy).toHaveBeenCalled();
220-
}));
241+
});
221242

222-
it('should not toggle item on click when disabled input is set to true', fakeAsync(() => {
243+
it('should not toggle item on click when disabled input is set to true', async () => {
223244
component.disabled = true;
245+
fixture.changeDetectorRef.markForCheck();
224246
fixture.detectChanges();
225247

226248
const item = document.querySelector('.accordion-item') as HTMLElement;
@@ -233,9 +255,9 @@ describe('MDB Accordion', () => {
233255

234256
button.click();
235257
fixture.detectChanges();
236-
flush();
258+
await fixture.whenStable();
237259

238260
expect(button.classList).toContain('collapsed');
239261
expect(itemCollapse.classList).not.toContain('show');
240-
}));
262+
});
241263
});

0 commit comments

Comments
 (0)