• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.23
/src/slide/slide-container.component.ts
1
import { ThyAbstractOverlayContainer, ThyPortalOutlet } from 'ngx-tethys/core';
2
import { helpers } from 'ngx-tethys/util';
3
import { Observable, Subject } from 'rxjs';
4
import { filter, startWith, takeUntil } from 'rxjs/operators';
5

6
import { AnimationEvent } from '@angular/animations';
7
import { ViewportRuler } from '@angular/cdk/overlay';
8
import { PortalModule } from '@angular/cdk/portal';
9
import { DOCUMENT } from '@angular/common';
10
import { ChangeDetectorRef, Component, ElementRef, NgZone, OnDestroy, Renderer2, ViewChild, inject } from '@angular/core';
11
import { useHostRenderer } from '@tethys/cdk/dom';
12

13
import { thySlideAnimations } from './slide-animations';
14
import { slideAbstractOverlayOptions, ThySlideConfig, ThySlideFromTypes } from './slide.config';
15

16
/**
1✔
17
 * @private
UNCOV
18
 */
×
19
@Component({
20
    selector: 'thy-slide-container',
UNCOV
21
    template: ` <ng-template thyPortalOutlet></ng-template> `,
×
22
    animations: [thySlideAnimations.slideContainer],
23
    host: {
UNCOV
24
        class: 'thy-slide-container',
×
25
        '[class.thy-slide-push]': 'isPush',
26
        '[class.thy-slide-side]': 'isSide',
UNCOV
27
        '[class.thy-slide-over]': '!isPush && !isSide',
×
UNCOV
28
        tabindex: '-1',
×
UNCOV
29
        '[attr.role]': `'slide'`,
×
30
        '[@slideContainer]': 'animationState',
31
        '(@slideContainer.start)': 'onAnimationStart($event)',
UNCOV
32
        '(@slideContainer.done)': 'onAnimationDone($event)',
×
33
        '[style.width.px]': 'slideContainerStyles.width',
UNCOV
34
        '[style.height.px]': 'slideContainerStyles.height',
×
35
        '[style.max-height.px]': 'slideContainerStyles.height'
36
    },
UNCOV
37
    imports: [PortalModule, ThyPortalOutlet]
×
38
})
UNCOV
39
export class ThySlideContainer extends ThyAbstractOverlayContainer implements OnDestroy {
×
40
    private elementRef = inject(ElementRef);
UNCOV
41
    private document = inject(DOCUMENT);
×
42
    config = inject(ThySlideConfig);
UNCOV
43
    private renderer = inject(Renderer2);
×
44
    private viewportRuler = inject(ViewportRuler);
UNCOV
45
    private readonly ngZone = inject(NgZone);
×
46

47
    @ViewChild(ThyPortalOutlet, { static: true })
48
    portalOutlet: ThyPortalOutlet;
UNCOV
49

×
50
    animationOpeningDone: Observable<AnimationEvent>;
51

UNCOV
52
    animationClosingDone: Observable<AnimationEvent>;
×
UNCOV
53

×
UNCOV
54
    animationState: ThySlideFromTypes = 'void';
×
UNCOV
55

×
UNCOV
56
    slideContainerStyles: { width?: number; height?: number } = {};
×
UNCOV
57

×
UNCOV
58
    private drawerContainerElement: HTMLElement;
×
UNCOV
59

×
UNCOV
60
    private ngUnsubscribe$ = new Subject<void>();
×
UNCOV
61

×
UNCOV
62
    private hostRenderer = useHostRenderer();
×
UNCOV
63

×
UNCOV
64
    get isPush() {
×
UNCOV
65
        return this.config.mode === 'push' && !!this.drawerContainerElement;
×
66
    }
UNCOV
67

×
UNCOV
68
    get isSide() {
×
69
        return this.config.mode === 'side' && !!this.drawerContainerElement;
UNCOV
70
    }
×
UNCOV
71

×
UNCOV
72
    private get isLeftOrRight(): boolean {
×
73
        return this.config.from === 'left' || this.config.from === 'right';
74
    }
UNCOV
75

×
UNCOV
76
    private get hostOffset() {
×
77
        let offset = 0;
UNCOV
78
        if (this.isLeftOrRight) {
×
UNCOV
79
            offset = this.elementRef.nativeElement.clientWidth + this.config.offset || 0;
×
80
        } else {
UNCOV
81
            offset = this.elementRef.nativeElement.clientHeight + this.config.offset || 0;
×
UNCOV
82
        }
×
83
        return offset;
84
    }
85

86
    private get transform() {
UNCOV
87
        switch (this.config.from) {
×
UNCOV
88
            case 'left':
×
UNCOV
89
                return `translateX(${this.hostOffset}px)`;
×
UNCOV
90
            case 'right':
×
UNCOV
91
                return `translateX(-${this.hostOffset}px)`;
×
92
            case 'top':
93
                return `translateY(${this.hostOffset}px)`;
UNCOV
94
            case 'bottom':
×
UNCOV
95
                return `translateY(${this.hostOffset}px)`;
×
UNCOV
96
        }
×
97
    }
UNCOV
98

×
99
    private get drawerContainerElementClass() {
100
        return `thy-slide-${this.config.mode}-drawer-container`;
101
    }
102

103
    constructor() {
UNCOV
104
        const changeDetectorRef = inject(ChangeDetectorRef);
×
105

106
        super(slideAbstractOverlayOptions, changeDetectorRef);
107
        this.animationOpeningDone = this.animationStateChanged.pipe(
UNCOV
108
            filter((event: AnimationEvent) => {
×
109
                return event.phaseName === 'done' && event.toState === this.animationState;
110
            })
111
        );
UNCOV
112
        this.animationClosingDone = this.animationStateChanged.pipe(
×
UNCOV
113
            filter((event: AnimationEvent) => {
×
114
                return event.phaseName === 'done' && event.toState === 'exit';
115
            })
116
        );
UNCOV
117
        this.setDrawerContainerElement();
×
UNCOV
118
        this.checkContainerWithinViewport();
×
119
        this.addDrawerContainerElementClass();
120
    }
121

UNCOV
122
    private setDrawerContainerElement() {
×
UNCOV
123
        if (typeof this.config.drawerContainer === 'string') {
×
124
            this.drawerContainerElement = this.config.drawerContainer && document.querySelector(this.config.drawerContainer);
UNCOV
125
        }
×
UNCOV
126
        if (this.config.drawerContainer instanceof ElementRef) {
×
127
            this.drawerContainerElement = this.config.drawerContainer.nativeElement;
128
        }
129
        if (this.config.drawerContainer instanceof HTMLElement) {
UNCOV
130
            this.drawerContainerElement = this.config.drawerContainer as HTMLElement;
×
UNCOV
131
        }
×
132
    }
UNCOV
133

×
UNCOV
134
    private setSlideContainerStyles() {
×
135
        let width, height, top, left;
136
        const drawerContainerElementRect = (this.drawerContainerElement || document.body).getBoundingClientRect();
137
        if (this.isLeftOrRight) {
UNCOV
138
            height = drawerContainerElementRect.height;
×
UNCOV
139
            top = drawerContainerElementRect.top;
×
UNCOV
140
            this.hostRenderer.setStyle('top', `${top}px`);
×
141
        } else {
142
            width = drawerContainerElementRect.width;
UNCOV
143
            left = drawerContainerElementRect.left;
×
144
            this.hostRenderer.setStyle('left', `${left}px`);
UNCOV
145
        }
×
146
        this.slideContainerStyles = {
147
            width: width,
UNCOV
148
            height: height
×
149
        };
150
    }
UNCOV
151

×
152
    private checkContainerWithinViewport() {
153
        this.viewportRuler
UNCOV
154
            .change(100)
×
155
            .pipe(startWith(null), takeUntil(this.ngUnsubscribe$))
156
            .subscribe(() => {
UNCOV
157
                this.ngZone.run(() => this.setSlideContainerStyles());
×
UNCOV
158
            });
×
UNCOV
159
    }
×
UNCOV
160

×
161
    private addDrawerContainerElementClass() {
162
        if (this.drawerContainerElement) {
1✔
163
            this.renderer.addClass(this.drawerContainerElement, this.drawerContainerElementClass);
1✔
164
        }
165
    }
166

167
    private removeDrawerContainerElementClass() {
1✔
168
        if (this.drawerContainerElement) {
169
            this.renderer.removeClass(this.drawerContainerElement, this.drawerContainerElementClass);
170
        }
171
    }
172

173
    private setDrawerContainerElementStyle() {
174
        if (this.isSide) {
175
            this.renderer.setStyle(this.drawerContainerElement, `margin-${this.config.from}`, `${this.hostOffset}px`);
176
        } else if (this.isPush) {
177
            this.renderer.setStyle(this.drawerContainerElement, `transform`, this.transform);
178
        }
179
    }
180

181
    private removeDrawerContainerElementStyle() {
182
        if (this.isSide) {
183
            this.renderer.removeStyle(this.drawerContainerElement, `margin-${this.config.from}`);
184
        } else if (this.isPush) {
185
            this.renderer.removeStyle(this.drawerContainerElement, `transform`);
186
        }
187
    }
188

189
    beforeAttachPortal(): void {
190
        if (this.config.offset) {
191
            this.hostRenderer.setStyle(this.config.from, `${this.config.offset}px`);
192
            this.animationState = helpers.camelCase(['offset', this.config.from]) as ThySlideFromTypes;
193
        } else {
194
            this.animationState = this.config.from;
195
        }
196
        this.setDrawerContainerElementStyle();
197
    }
198

199
    beforeDetachPortal(): void {
200
        this.removeDrawerContainerElementStyle();
201
    }
202

203
    onAnimationDone(event: AnimationEvent) {
204
        this.animationStateChanged.emit(event);
205
    }
206

207
    onAnimationStart(event: AnimationEvent) {
208
        this.animationStateChanged.emit(event);
209
    }
210

211
    ngOnDestroy() {
212
        super.destroy();
213
        this.removeDrawerContainerElementClass();
214
        this.ngUnsubscribe$.next();
215
        this.ngUnsubscribe$.complete();
216
    }
217
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc