• 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

5.95
/src/flexible-text/flexible-text.component.ts
1
import { ContentObserver } from '@angular/cdk/observers';
2
import {
3
    AfterContentInit,
4
    Component,
5
    ElementRef,
6
    NgZone,
7
    OnDestroy,
8
    TemplateRef,
9
    numberAttribute,
10
    inject,
11
    input,
12
    effect
13
} from '@angular/core';
14
import { ThyPlacement } from 'ngx-tethys/core';
15
import { ThyTooltipDirective } from 'ngx-tethys/tooltip';
16
import { isUndefinedOrNull } from 'ngx-tethys/util';
1✔
17
import { useHostRenderer } from '@tethys/cdk/dom';
1✔
18
import { from, Observable, Subject, Subscription } from 'rxjs';
UNCOV
19
import { debounceTime, take, takeUntil } from 'rxjs/operators';
×
UNCOV
20

×
UNCOV
21
/**
×
22
 * 文本提示组件,支持组件 thy-flexible-text 和指令 [thyFlexibleText] 两种方式
UNCOV
23
 * @name thy-flexible-text,[thyFlexibleText]
×
UNCOV
24
 */
×
UNCOV
25
@Component({
×
26
    selector: 'thy-flexible-text,[thyFlexibleText]',
27
    exportAs: 'thyFlexibleText',
28
    templateUrl: './flexible-text.component.html',
29
    hostDirectives: [ThyTooltipDirective]
UNCOV
30
})
×
UNCOV
31
export class ThyFlexibleText implements AfterContentInit, OnDestroy {
×
UNCOV
32
    private elementRef = inject(ElementRef);
×
UNCOV
33
    private contentObserver = inject(ContentObserver);
×
UNCOV
34
    private ngZone = inject(NgZone);
×
UNCOV
35
    tooltipDirective = inject(ThyTooltipDirective);
×
UNCOV
36

×
UNCOV
37
    isOverflow = false;
×
UNCOV
38

×
UNCOV
39
    subscription: Subscription | null = null;
×
UNCOV
40

×
UNCOV
41
    /**
×
UNCOV
42
     * 触发提示方式
×
UNCOV
43
     * @type hover | focus | click
×
UNCOV
44
     * @default hover
×
45
     */
UNCOV
46
    readonly trigger = input<'hover' | 'focus' | 'click'>(undefined, { alias: 'thyTooltipTrigger' });
×
UNCOV
47

×
UNCOV
48
    /**
×
UNCOV
49
     * 自定义class类,如果不设置默认会包含 `flexible-text-container`
×
50
     */
51
    readonly thyContainerClass = input<string>();
UNCOV
52

×
UNCOV
53
    /**
×
UNCOV
54
     * 需要展示的全部内容
×
UNCOV
55
     * @type string | TemplateRef<HTMLElement>
×
56
     */
57
    readonly thyTooltipContent = input<string | TemplateRef<HTMLElement>>();
UNCOV
58

×
UNCOV
59
    /**
×
UNCOV
60
     * tooltip 的提示位置
×
UNCOV
61
     * @type top | bottom | left | right
×
62
     * @default top
63
     */
UNCOV
64
    readonly thyTooltipPlacement = input<ThyPlacement>();
×
UNCOV
65

×
UNCOV
66
    /**
×
UNCOV
67
     * tooltip 偏移量
×
68
     */
69
    readonly thyTooltipOffset = input<number, unknown>(undefined, { transform: numberAttribute });
UNCOV
70

×
71
    private destroy$ = new Subject<void>();
72

73
    private hostRenderer = useHostRenderer();
74

UNCOV
75
    static createResizeObserver(element: HTMLElement) {
×
76
        return new Observable(observer => {
77
            const resize = new ResizeObserver(entries => {
UNCOV
78
                observer.next(entries);
×
79
            });
UNCOV
80
            resize.observe(element);
×
UNCOV
81
            return () => {
×
82
                resize.disconnect();
83
            };
84
        });
UNCOV
85
    }
×
86

UNCOV
87
    constructor() {
×
88
        effect(() => {
89
            this.updateContainerClass();
UNCOV
90
        });
×
91
        effect(() => {
92
            const content = this.thyTooltipContent();
93
            if (this.tooltipDirective && content) {
94
                this.tooltipDirective.content = content;
95
            }
UNCOV
96
        });
×
UNCOV
97
        effect(() => {
×
98
            const placement = this.thyTooltipPlacement();
99
            if (this.tooltipDirective && placement) {
UNCOV
100
                this.tooltipDirective.placement = placement;
×
UNCOV
101
            }
×
UNCOV
102
        });
×
103
        effect(() => {
104
            const offset = this.thyTooltipOffset();
UNCOV
105
            if (this.tooltipDirective && !isUndefinedOrNull(offset)) {
×
106
                this.tooltipDirective.tooltipOffset = offset;
UNCOV
107
            }
×
108
        });
109
        effect(() => {
UNCOV
110
            const trigger = this.trigger();
×
UNCOV
111
            if (this.tooltipDirective && trigger) {
×
UNCOV
112
                this.tooltipDirective.trigger = trigger;
×
113
            }
114
        });
1✔
115
        this.tooltipDirective.thyTooltipDisabled = true;
1✔
116
    }
117

118
    ngAfterContentInit() {
119
        // Note: the zone may be nooped through `BootstrapOptions` when bootstrapping the root module. This means
120
        // the `onStable` will never emit any value.
121
        const onStable$ = this.ngZone.isStable ? from(Promise.resolve()) : this.ngZone.onStable.pipe(take(1));
122
        // Normally this isn't in the zone, but it can cause performance regressions for apps
123
        // using `zone-patch-rxjs` because it'll trigger a change detection when it unsubscribes.
1✔
124
        this.ngZone.runOutsideAngular(() => {
125
            // Wait for the next time period to avoid blocking the js thread.
126
            onStable$.pipe(takeUntil(this.destroy$)).subscribe(() => {
127
                this.contentObserver
128
                    .observe(this.elementRef)
129
                    .pipe(debounceTime(100), takeUntil(this.destroy$))
130
                    .subscribe(() => {
131
                        this.applyOverflow();
132
                    });
133

134
                ThyFlexibleText.createResizeObserver(this.elementRef.nativeElement)
135
                    .pipe(debounceTime(100), takeUntil(this.destroy$))
136
                    .subscribe(() => {
137
                        this.applyOverflow();
138
                    });
139
            });
140
        });
141
    }
142

143
    ngOnDestroy() {
144
        this.destroy$.next();
145
        this.tooltipDirective.hide();
146
    }
147

148
    applyOverflow() {
149
        const nativeElement = this.elementRef.nativeElement;
150
        if (nativeElement.clientWidth < nativeElement.scrollWidth || nativeElement.clientHeight < nativeElement.scrollHeight) {
151
            this.isOverflow = true;
152
        } else {
153
            this.isOverflow = false;
154
        }
155
        this.tooltipDirective.thyTooltipDisabled = !this.isOverflow;
156
    }
157

158
    updateContainerClass() {
159
        const containerClass = isUndefinedOrNull(this.thyContainerClass()) ? 'flexible-text-container' : this.thyContainerClass();
160
        const flexibleTextClass = { 'text-truncate': true, [containerClass]: containerClass !== '' };
161
        this.hostRenderer.updateClassByMap(flexibleTextClass);
162
    }
163
}
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