Skip to content

Commit 8c15b75

Browse files
committed
refactor(offcanvas): animation classes, scrollbar behavior, cleanup
1 parent 8bdf397 commit 8c15b75

File tree

2 files changed

+64
-41
lines changed

2 files changed

+64
-41
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:host {
2+
display: none;
3+
}

projects/coreui-angular/src/lib/offcanvas/offcanvas/offcanvas.component.ts

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@ import {
66
HostListener,
77
Inject,
88
Input,
9-
OnChanges,
109
OnDestroy,
1110
OnInit,
1211
Output,
1312
PLATFORM_ID,
14-
Renderer2,
15-
SimpleChanges
13+
Renderer2
1614
} from '@angular/core';
17-
import { animate, state, style, transition, trigger } from '@angular/animations';
15+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
16+
import { animate, AnimationEvent, state, style, transition, trigger } from '@angular/animations';
1817
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
1918
import { Subscription } from 'rxjs';
2019

21-
import { OffcanvasService } from '../offcanvas.service';
2220
import { BackdropService } from '../../backdrop/backdrop.service';
23-
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
21+
import { OffcanvasService } from '../offcanvas.service';
2422

2523
let nextId = 0;
2624

@@ -29,29 +27,30 @@ let nextId = 0;
2927
animations: [
3028
trigger('showHide', [
3129
state(
32-
'true',
30+
'visible',
3331
style({
34-
visibility: 'visible'
32+
// visibility: 'visible'
3533
})
3634
),
3735
state(
38-
'false',
36+
'hidden',
3937
style({
40-
visibility: 'hidden'
38+
// visibility: 'hidden'
4139
})
4240
),
43-
transition('true => false', [animate('300ms')])
41+
transition('visible <=> *', [animate('300ms')])
4442
])
4543
],
4644
templateUrl: './offcanvas.component.html',
4745
styleUrls: ['./offcanvas.component.scss'],
4846
exportAs: 'cOffcanvas'
4947
})
50-
export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
48+
export class OffcanvasComponent implements OnInit, OnDestroy {
49+
5150
static ngAcceptInputType_scroll: BooleanInput;
5251

5352
constructor(
54-
@Inject(DOCUMENT) private document: any,
53+
@Inject(DOCUMENT) private document: Document,
5554
@Inject(PLATFORM_ID) private platformId: any,
5655
private renderer: Renderer2,
5756
private hostElement: ElementRef,
@@ -96,6 +95,7 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
9695
private _scroll = false;
9796

9897
@Input() id = `offcanvas-${this.placement}-${nextId++}`;
98+
9999
/**
100100
* Default role for offcanvas. [docs]
101101
* @type string
@@ -113,32 +113,32 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
113113
/**
114114
* Toggle the visibility of offcanvas component.
115115
* @type boolean
116+
* @default false
116117
*/
117118
@Input()
118119
set visible(value: boolean) {
119120
this._visible = coerceBooleanProperty(value);
120-
if (value) {
121+
if (this._visible) {
121122
this.setBackdrop(this.backdrop);
122123
this.setFocus();
123124
} else {
124125
this.setBackdrop(false);
125126
}
126-
this.setScroll();
127127
this.visibleChange.emit(value);
128128
}
129129

130130
get visible(): boolean {
131131
return this._visible;
132132
}
133133

134-
private _visible!: boolean;
134+
private _visible: boolean = false;
135135

136136
/**
137137
* Event triggered on visible change.
138138
*/
139139
@Output() visibleChange = new EventEmitter<boolean>();
140140

141-
private activeBackdrop!: any;
141+
private activeBackdrop!: HTMLDivElement;
142142
private scrollbarWidth!: string;
143143

144144
private stateToggleSubscription!: Subscription;
@@ -149,7 +149,7 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
149149
return {
150150
offcanvas: true,
151151
[`offcanvas-${this.placement}`]: !!this.placement,
152-
show: this.visible
152+
show: this.show
153153
};
154154
}
155155

@@ -164,8 +164,47 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
164164
}
165165

166166
@HostBinding('@showHide')
167-
get animateType(): boolean {
168-
return this.visible;
167+
get animateTrigger(): string {
168+
return this.visible ? 'visible' : 'hidden';
169+
}
170+
171+
get show(): boolean {
172+
return this.visible && this._show;
173+
}
174+
175+
set show(value: boolean) {
176+
this._show = value;
177+
}
178+
179+
private _show = false;
180+
181+
@HostListener('@showHide.start', ['$event'])
182+
animateStart(event: AnimationEvent) {
183+
const scrollbarWidth = this.scrollbarWidth;
184+
if (event.toState === 'visible') {
185+
if (!this.scroll) {
186+
this.renderer.setStyle(this.document.body, 'overflow', 'hidden');
187+
this.renderer.setStyle(this.document.body, 'padding-right', scrollbarWidth);
188+
}
189+
this.renderer.addClass(this.hostElement.nativeElement, 'showing');
190+
} else {
191+
this.renderer.addClass(this.hostElement.nativeElement, 'hiding');
192+
}
193+
}
194+
195+
@HostListener('@showHide.done', ['$event'])
196+
animateDone(event: AnimationEvent) {
197+
setTimeout(() => {
198+
if (event.toState === 'visible') {
199+
this.renderer.removeClass(this.hostElement.nativeElement, 'showing');
200+
}
201+
if (event.toState === 'hidden') {
202+
this.renderer.removeClass(this.hostElement.nativeElement, 'hiding');
203+
this.renderer.removeStyle(this.document.body, 'overflow');
204+
this.renderer.removeStyle(this.document.body, 'paddingRight');
205+
}
206+
});
207+
this.show = this.visible;
169208
}
170209

171210
@HostListener('document:keydown', ['$event'])
@@ -181,22 +220,17 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
181220
}
182221

183222
ngOnInit(): void {
184-
this.setScroll();
185223
this.scrollbarWidth = this.backdropService.scrollbarWidth;
186224
this.stateToggleSubscribe();
225+
// hotfix to avoid end offcanvas flicker on first render
226+
this.renderer.setStyle(this.hostElement.nativeElement, 'display', 'flex');
187227
}
188228

189229
ngOnDestroy(): void {
190230
this.offcanvasService.toggle({ show: false, id: this.id });
191231
this.stateToggleSubscribe(false);
192232
}
193233

194-
ngOnChanges(changes: SimpleChanges): void {
195-
if (changes['scroll']) {
196-
this.setScroll();
197-
}
198-
}
199-
200234
private stateToggleSubscribe(subscribe: boolean = true): void {
201235
if (subscribe) {
202236
this.stateToggleSubscription =
@@ -237,18 +271,4 @@ export class OffcanvasComponent implements OnChanges, OnInit, OnDestroy {
237271
setTimeout(() => this.hostElement.nativeElement.focus());
238272
}
239273
}
240-
241-
setScroll() {
242-
if (this.visible) {
243-
if (!this.scroll) {
244-
this.renderer.setStyle(this.document.body, 'overflow', 'hidden');
245-
this.renderer.setStyle(this.document.body, 'paddingRight.px', '0');
246-
}
247-
return;
248-
}
249-
if (!this.scroll) {
250-
this.renderer.removeStyle(this.document.body, 'overflow');
251-
this.renderer.removeStyle(this.document.body, 'paddingRight');
252-
}
253-
}
254274
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy