1
- import { AfterContentInit , Component , ContentChild , ElementRef , HostBinding , Input } from '@angular/core' ;
2
- import { NgClass , NgTemplateOutlet } from '@angular/common' ;
1
+ import {
2
+ AfterContentInit ,
3
+ afterRender ,
4
+ Component ,
5
+ computed ,
6
+ contentChild ,
7
+ ElementRef ,
8
+ inject ,
9
+ input ,
10
+ OnDestroy ,
11
+ signal
12
+ } from '@angular/core' ;
13
+ import { DOCUMENT , NgClass , NgTemplateOutlet } from '@angular/common' ;
3
14
import { BreakpointObserver } from '@angular/cdk/layout' ;
4
15
5
16
import { CollapseDirective } from '../collapse' ;
6
17
import { Colors } from '../coreui.types' ;
7
18
import { ThemeDirective } from '../shared' ;
19
+ import { Subscription } from 'rxjs' ;
8
20
9
21
// todo: fix container prop issue not rendering children
10
22
// todo: workaround - use <c-container> component directly in template
@@ -15,79 +27,106 @@ import { ThemeDirective } from '../shared';
15
27
standalone : true ,
16
28
imports : [ NgClass , NgTemplateOutlet ] ,
17
29
hostDirectives : [ { directive : ThemeDirective , inputs : [ 'colorScheme' ] } ] ,
18
- host : { class : 'navbar ' }
30
+ host : { '[ class]' : 'hostClasses()' , '[attr.role]' : 'role() ' }
19
31
} )
20
- export class NavbarComponent implements AfterContentInit {
32
+ export class NavbarComponent implements AfterContentInit , OnDestroy {
33
+ readonly #breakpointObserver = inject ( BreakpointObserver ) ;
34
+ readonly #document = inject ( DOCUMENT ) ;
35
+ readonly #hostElement = inject ( ElementRef ) ;
36
+
21
37
/**
22
38
* Sets the color context of the component to one of CoreUI’s themed colors.
23
39
* @type Colors
24
40
*/
25
- @Input ( ) color ?: Colors ;
41
+ readonly color = input < Colors > ( ) ;
42
+
26
43
/**
27
44
* Defines optional container wrapping children elements.
28
45
*/
29
- @Input ( ) container ?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'fluid' ;
46
+ readonly container = input < boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'fluid' > ( ) ;
47
+
30
48
/**
31
49
* Defines the responsive breakpoint to determine when content collapses.
32
50
*/
33
- @Input ( ) expand ?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' ;
51
+ readonly expand = input < boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' > ( ) ;
52
+
34
53
/**
35
54
* Place component in non-static positions.
36
55
*/
37
- @ Input ( ) placement ?: 'fixed-top' | 'fixed-bottom' | 'sticky-top' ;
56
+ readonly placement = input < 'fixed-top' | 'fixed-bottom' | 'sticky-top' > ( ) ;
38
57
39
- @ ContentChild ( CollapseDirective ) collapse ! : CollapseDirective ;
58
+ readonly role = input ( 'navigation' ) ;
40
59
41
- @HostBinding ( 'attr.role' )
42
- @Input ( )
43
- role = 'navigation' ;
60
+ readonly collapse = contentChild ( CollapseDirective ) ;
44
61
45
- constructor (
46
- private hostElement : ElementRef ,
47
- private breakpointObserver : BreakpointObserver
48
- ) { }
49
-
50
- @HostBinding ( 'class' )
51
- get hostClasses ( ) : any {
52
- const expandClassSuffix : string = this . expand === true ? '' : `-${ this . expand } ` ;
62
+ readonly hostClasses = computed ( ( ) => {
63
+ const color = this . color ( ) ;
64
+ const expand = this . expand ( ) ;
65
+ const expandClassSuffix : string = expand === true ? '' : `-${ expand } ` ;
66
+ const placement = this . placement ( ) ;
53
67
return {
54
68
navbar : true ,
55
- [ `navbar-expand${ expandClassSuffix } ` ] : ! ! this . expand ,
56
- [ `bg-${ this . color } ` ] : ! ! this . color ,
57
- [ `${ this . placement } ` ] : ! ! this . placement
58
- } ;
59
- }
69
+ [ `navbar-expand${ expandClassSuffix } ` ] : ! ! expand ,
70
+ [ `bg-${ color } ` ] : ! ! color ,
71
+ [ `${ placement } ` ] : ! ! placement
72
+ } as Record < string , boolean > ;
73
+ } ) ;
60
74
61
- get containerClass ( ) : string {
62
- return `container${ this . container !== true ? '-' + this . container : '' } ` ;
63
- }
75
+ readonly containerClass = computed ( ( ) => {
76
+ const container = this . container ( ) ;
77
+ return `container${ container !== true ? '-' + container : '' } ` ;
78
+ } ) ;
64
79
65
- get breakpoint ( ) : string | boolean {
66
- if ( typeof this . expand === 'string' ) {
67
- return (
68
- getComputedStyle ( this . hostElement . nativeElement ) ?. getPropertyValue ( `--cui-breakpoint-${ this . expand } ` ) ?? false
69
- ) ;
80
+ readonly computedStyle = signal < string > ( '' ) ;
81
+
82
+ readonly afterNextRenderFn = afterRender ( {
83
+ read : ( ) => {
84
+ const expand = this . expand ( ) ;
85
+ if ( typeof expand === 'string' ) {
86
+ const computedStyle =
87
+ this . #document. defaultView
88
+ ?. getComputedStyle ( this . #hostElement. nativeElement )
89
+ ?. getPropertyValue ( `--cui-breakpoint-${ expand } ` ) ?? false ;
90
+ computedStyle && this . computedStyle . set ( computedStyle ) ;
91
+ }
92
+ }
93
+ } ) ;
94
+
95
+ readonly breakpoint = computed ( ( ) => {
96
+ const expand = this . expand ( ) ;
97
+ if ( typeof expand === 'string' ) {
98
+ return this . computedStyle ( ) ;
70
99
}
71
100
return false ;
72
- }
101
+ } ) ;
102
+
103
+ #observer! : Subscription ;
73
104
74
105
ngAfterContentInit ( ) : void {
75
- if ( this . breakpoint ) {
76
- const onBreakpoint = `(min-width: ${ this . breakpoint } )` ;
77
- this . breakpointObserver . observe ( [ onBreakpoint ] ) . subscribe ( ( result ) => {
78
- if ( this . collapse ) {
79
- const animate = this . collapse . animate ;
80
- // todo: collapse animate input signal setter
81
- this . collapse . animate = false ;
82
- this . collapse . toggle ( false ) ;
83
- setTimeout ( ( ) => {
84
- this . collapse . toggle ( result . matches ) ;
106
+ const breakpoint = this . breakpoint ( ) ;
107
+ if ( breakpoint ) {
108
+ const onBreakpoint = `(min-width: ${ breakpoint } )` ;
109
+ this . #observer = this . #breakpointObserver
110
+ . observe ( [ onBreakpoint ] )
111
+ . pipe ( )
112
+ . subscribe ( ( result ) => {
113
+ const collapse = this . collapse ( ) ;
114
+ if ( collapse ) {
115
+ const animate = collapse . animate ( ) ;
116
+ collapse . animate . set ( false ) ;
117
+ collapse . toggle ( false ) ;
85
118
setTimeout ( ( ) => {
86
- this . collapse . animate = animate ;
119
+ collapse . toggle ( result . matches ) ;
120
+ setTimeout ( ( ) => {
121
+ collapse . animate . set ( animate ) ;
122
+ } ) ;
87
123
} ) ;
88
- } ) ;
89
- }
90
- } ) ;
124
+ }
125
+ } ) ;
91
126
}
92
127
}
128
+
129
+ ngOnDestroy ( ) : void {
130
+ this . #observer?. unsubscribe ( ) ;
131
+ }
93
132
}
0 commit comments