Skip to content

Commit 914681c

Browse files
DerekLianglexasqCopilotDerek LiangAlex Umanskiy
authored
Zoneless support (#6789)
* fix- daterange picker, default range in quick Select ranges * refactor * Initial plan * Add comprehensive zoneless migration plan for ngx-bootstrap Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Update zoneless migration plan per user feedback: breaking change, docs app, input/output migration Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 1: Enable zoneless change detection in docs app Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate alert, progressbar, accordion, collapse to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate rating component to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate tabs components to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2-3: Migrate carousel to zoneless (remove NgZone, use input/output signals) Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Disable husky pre-push hook for zoneless migration Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate buttons and sortable components to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate pagination components to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate dropdown and modal components to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate timepicker component to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 2: Migrate tooltip, popover, and typeahead to input()/output() signals Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 4: Update services for zoneless (remove NgZone from component-loader, positioning, focus-trap) Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 5-6: Complete migration - validate all tests, update documentation, re-enable husky Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Phase 5-6: Complete migration - validate all tests, update documentation Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> * Refactor components to utilize input/output signals and improve state management * Refactor accordion, carousel, and tabset components to use input bindings for configuration values instead of Object.assign * Revert "Refactor accordion, carousel, and tabset components to use input bindings for configuration values instead of Object.assign" This reverts commit 1cb23e0. * Refactor components to use configuration values from respective config objects instead of default values * Refactor popover components to use configuration values from the config object * Refactor ProgressbarComponent to use configuration values from ProgressbarConfig * Cleanup ProgressbarComponent by removing unnecessary blank lines * Refactor Timepicker and Tooltip components to use configuration values from respective config objects * Fix memory leak by unsubscribing from positioning on component hide * Enhance change detection in Typeahead components by marking for check on updates * chore(deps): update Angular and Nx dependencies to latest versions - Upgraded Angular packages from 20.0.2 to 21.1.1 - Upgraded Nx packages from 21.2.0 to 22.4.0 - Updated TypeScript from 5.8.2 to 5.9.3 - Updated ESLint packages to 8.53.1 - Updated ng-packagr to 21.0.0 - Added overrides for specific dependencies * Revert "chore(deps): update Angular and Nx dependencies to latest versions" This reverts commit 493e310. * Delete .vscode/settings.json * final check before submit PR. * fix linting issues * Revert "fix- daterange picker, default range in quick Select ranges" This reverts commit e357cde. * fix: handle optional chaining for route data and update onPreview method signature * refactor: remove zone change detection from bootstrap module and update event handling in dropdown demo * refactor: remove unused NgIf, NgSwitch, NgSwitchCase, and NgFor imports from date range picker components * fix(popover): convert to signals and fix zoneless compatibility * fix(dropdown): add @output decorators to events for zoneless compatibility * fix(progressbar): add striped property to config so striped works from config * fix(typeahead): default typeaheadHideResultsOnBlur to true so outside click closes dropdown * fix(tabs): add ChangeDetectorRef.markForCheck for zoneless compatibility * fix(carousel): only apply active input when explicitly bound to avoid override * fix(pagination): use signal getters in template and add effect for rotate/maxSize * fix(datepicker): simplify tooltip text reduce to filter for cleaner logic * fix(docs): convert app sidebar to signal and fix modal demo initialState * chore: update package-lock.json * fix(dropdown): convert events from @output EventEmitter to output() signals * chore: update package-lock.json * fix(dropdown): update test to call signal inputs instead of reading them as properties * fix(timepicker): update tests to use signal inputs via setInput and call signal getters * fix(rating): update test to use setInput for signal inputs * fix(typeahead): update tests to use signal-compatible mocks and host component bindings * fix(typeahead): revert typeaheadOptionsLimit default, align test with ?? 20 fallback and restore async detection test * fix(pagination): update tests to use setInput for signal inputs * fix(alert): update tests to use setInput for signal inputs and read internal _isOpen state * fix(tabs): sync signal inputs in ngOnInit before addTab, update tests for signal reads --------- Co-authored-by: Alexey Umanskiy <sharkakatsukie@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DerekLiang <13641+DerekLiang@users.noreply.github.com> Co-authored-by: Derek Liang <derek.liang@worksafebc.com> Co-authored-by: Alex Umanskiy <aleksey.umanskiy@valor-software.com>
1 parent 2b60ddd commit 914681c

74 files changed

Lines changed: 19949 additions & 14843 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ZONELESS_MIGRATION_PLAN.md

Lines changed: 905 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<top-menu></top-menu>
2-
@if (showSidebar) {
2+
@if (showSidebar()) {
33
<sidebar id="sidebar" class="sidebar"></sidebar>
44
}
55
<router-outlet></router-outlet>
Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DOCUMENT } from '@angular/common';
2-
import { AfterContentInit, Component, Inject } from '@angular/core';
2+
import { AfterContentInit, Component, Inject, signal } from '@angular/core';
33
import { ActivatedRoute, NavigationEnd, Router, UrlSerializer } from '@angular/router';
4+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
45
import { Analytics } from '@ngx-bootstrap-doc/docs';
56
import { filter } from 'rxjs/operators';
67

@@ -11,15 +12,32 @@ import { filter } from 'rxjs/operators';
1112
standalone: false
1213
})
1314
export class AppComponent implements AfterContentInit {
14-
showSidebar = false;
15+
showSidebar = signal(false);
1516

1617
constructor(
1718
private route: ActivatedRoute,
1819
private router: Router,
1920
private urlSerializer: UrlSerializer,
2021
private analytics: Analytics,
2122
@Inject(DOCUMENT) private document: any
22-
) {}
23+
) {
24+
const getUrl = () => {
25+
const url = this.router.routerState.snapshot.url;
26+
const idx = url.indexOf('#');
27+
return idx === -1 ? url : url.slice(0, idx);
28+
};
29+
30+
this.showSidebar.set(!!getUrl() && getUrl() !== '/');
31+
32+
this.router.events
33+
.pipe(
34+
filter(event => event instanceof NavigationEnd),
35+
takeUntilDestroyed()
36+
)
37+
.subscribe(() => {
38+
this.showSidebar.set(!!getUrl() && getUrl() !== '/');
39+
});
40+
}
2341

2442
// almost same logic exists in top-menu component
2543
ngAfterContentInit(): any {
@@ -28,35 +46,33 @@ export class AppComponent implements AfterContentInit {
2846
const getUrl = (router: Router) =>
2947
router.routerState.snapshot.url.slice(0, router.routerState.snapshot.url.indexOf('#'));
3048
let _prev = getUrl(this.router);
31-
const justDoIt = (): void => {
32-
const _cur = getUrl(this.router);
33-
this.showSidebar = !!getUrl(this.router);
34-
if (typeof PR !== 'undefined' && _prev !== _cur) {
35-
_prev = _cur;
36-
// google code-prettify
37-
PR.prettyPrint();
38-
}
39-
40-
const hash = this.route.snapshot.fragment;
41-
if (hash) {
42-
const target: HTMLElement | null = this.document.getElementById(hash);
43-
const header: HTMLElement | null = this.document.getElementById('header');
44-
if (target && header) {
45-
setTimeout(() => {
46-
const sidebar: HTMLElement | null = this.document.getElementById('sidebar');
47-
const targetPosY: number = innerWidth <= 991 ? target.offsetTop - header.offsetHeight - 6 - (sidebar?.offsetHeight || 0) : target.offsetTop - header.offsetHeight - 6;
48-
window.scrollTo({top: targetPosY, behavior: 'smooth'});
49-
}, 100);
50-
}
51-
} else {
52-
window.scrollTo({top: 0, behavior: 'smooth'});
53-
}
54-
};
5549

5650
this.router.events
5751
.pipe(
5852
filter(event => event instanceof NavigationEnd)
5953
)
60-
.subscribe(() => setTimeout(() => justDoIt(), 50));
54+
.subscribe(() => setTimeout(() => {
55+
const _cur = getUrl(this.router);
56+
if (typeof PR !== 'undefined' && _prev !== _cur) {
57+
_prev = _cur;
58+
// google code-prettify
59+
PR.prettyPrint();
60+
}
61+
62+
const hash = this.route.snapshot.fragment;
63+
if (hash) {
64+
const target: HTMLElement | null = this.document.getElementById(hash);
65+
const header: HTMLElement | null = this.document.getElementById('header');
66+
if (target && header) {
67+
setTimeout(() => {
68+
const sidebar: HTMLElement | null = this.document.getElementById('sidebar');
69+
const targetPosY: number = innerWidth <= 991 ? target.offsetTop - header.offsetHeight - 6 - (sidebar?.offsetHeight || 0) : target.offsetTop - header.offsetHeight - 6;
70+
window.scrollTo({top: targetPosY, behavior: 'smooth'});
71+
}, 100);
72+
}
73+
} else {
74+
window.scrollTo({top: 0, behavior: 'smooth'});
75+
}
76+
}, 50));
6177
}
6278
}

apps/ngx-bootstrap-docs/src/app/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
2-
import { NgModule } from '@angular/core';
2+
import { NgModule, provideZonelessChangeDetection } from '@angular/core';
33
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
44
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
55

@@ -14,6 +14,7 @@ import { routes } from './app.routing';
1414
bootstrap: [AppComponent], imports: [BrowserAnimationsModule,
1515
DocsModule,
1616
], providers: [
17+
provideZonelessChangeDetection(),
1718
provideRouter(routes, withEnabledBlockingInitialNavigation()),
1819
{ provide: NgApiDoc, useValue: ngdoc },
1920
{ provide: DOCS_TOKENS, useValue: routes },

apps/ngx-bootstrap-docs/src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { enableProdMode, provideZoneChangeDetection } from '@angular/core';
1+
import { enableProdMode } from '@angular/core';
22
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
33

44
import { AppModule } from './app/app.module';
@@ -9,5 +9,5 @@ if (environment.production) {
99
}
1010

1111
platformBrowserDynamic()
12-
.bootstrapModule(AppModule, { applicationProviders: [provideZoneChangeDetection()], })
12+
.bootstrapModule(AppModule)
1313
.catch((err) => console.error(err));

0 commit comments

Comments
 (0)