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

atinc / ngx-tethys / #96

12 Aug 2025 06:20AM UTC coverage: 90.341% (+0.02%) from 90.324%
#96

push

web-flow
refactor(date-picker): migrate to signal for date-picker #TINFR-1463 (#3513)

* refactor(date-picker): migrate to signal for calendar header

* refactor(date-picker): migrate to signal for calendar footer

* refactor(date-picker): migrate to signal for calendar table

* refactor(date-picker): migrate to signal for date table cell

* refactor(date-picker): migrate to signal for date carousel

* refactor(date-picker): migrate to signal for inner-popup and date-popup

* refactor(date-picker): migrate to signal for pickers

5531 of 6813 branches covered (81.18%)

Branch coverage included in aggregate %.

342 of 367 new or added lines in 20 files covered. (93.19%)

66 existing lines in 11 files now uncovered.

13969 of 14772 relevant lines covered (94.56%)

904.1 hits per line

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

87.2
/src/date-picker/lib/popups/inner-popup.component.ts
1
import { ChangeDetectionStrategy, Component, model, input, output, Signal, TemplateRef, inject, effect } from '@angular/core';
2
import { FunctionProp, TinyDate, coerceBooleanProperty } from 'ngx-tethys/util';
3
import { DateHelperService } from '../../date-helper.service';
4
import { RangePartType } from '../../inner-types';
5
import { isAfterMoreThanLessOneYear, isAfterMoreThanOneDecade, isAfterMoreThanOneMonth, isAfterMoreThanOneYear } from '../../picker.util';
6
import { DisabledDateFn, ThyPanelMode } from '../../standard-types';
7
import { DateHeader } from '../date/date-header.component';
8
import { DateTable } from '../date/date-table.component';
9
import { ThyDatePickerLocale, injectLocale } from 'ngx-tethys/i18n';
10
import { ThyInputDirective } from 'ngx-tethys/input';
11
import { DecadeHeader } from '../decade/decade-header.component';
12
import { DecadeTable } from '../decade/decade-table.component';
13
import { MonthHeader } from '../month/month-header.component';
14
import { MonthTable } from '../month/month-table.component';
15
import { QuarterTable } from '../quarter/quarter-table.component';
16
import { YearHeader } from '../year/year-header.component';
17
import { YearTable } from '../year/year-table.component';
18

19
/**
20
 * @private
21
 */
22
@Component({
1✔
23
    changeDetection: ChangeDetectionStrategy.OnPush,
24
    // eslint-disable-next-line @angular-eslint/component-selector
206✔
25
    selector: 'inner-popup',
206✔
26
    exportAs: 'innerPopup',
206✔
27
    templateUrl: 'inner-popup.component.html',
206✔
28
    imports: [
206✔
29
        ThyInputDirective,
206✔
30
        DecadeHeader,
206✔
31
        DecadeTable,
206✔
32
        YearHeader,
206✔
33
        YearTable,
206✔
34
        MonthHeader,
206✔
35
        MonthTable,
36
        QuarterTable,
220!
UNCOV
37
        DateHeader,
×
38
        DateTable
39
    ],
220✔
40
    host: {
41
        class: 'thy-calendar-picker-inner-popup',
42
        '[class.thy-calendar-picker-inner-popup-with-range-input]': 'showDateRangeInput()'
206✔
43
    }
206✔
44
})
206✔
45
export class InnerPopup {
206✔
46
    private dateHelper = inject(DateHelperService);
206✔
47

206✔
48
    locale: Signal<ThyDatePickerLocale> = injectLocale('datePicker');
206✔
49

206✔
50
    readonly showWeek = input(false, { transform: coerceBooleanProperty });
206✔
51

206✔
52
    readonly isRange = input(false, { transform: coerceBooleanProperty });
206✔
53

500✔
54
    readonly activeDate = model<TinyDate>();
70✔
55

56
    readonly rangeActiveDate = input<TinyDate[]>(); // Range ONLY
57

58
    readonly disabledDate = input<DisabledDateFn>();
59

8✔
60
    readonly dateRender = input<FunctionProp<TemplateRef<Date> | string>>();
61

62
    readonly selectedValue = input<TinyDate[]>(); // Range ONLY
28!
63

28✔
64
    readonly hoverValue = input<TinyDate[]>(); // Range ONLY
65

66
    readonly panelMode = input(null, {
3✔
67
        transform: (value: ThyPanelMode | 'time') => {
3✔
68
            if (value === 'time') {
3✔
69
                return 'date';
3✔
70
            }
2✔
71
            return value;
2✔
72
        }
73
    });
74

1✔
75
    readonly timeZone = input<string>();
1✔
76

77
    readonly showDateRangeInput = input(false, { transform: coerceBooleanProperty });
78

79
    readonly partType = input<RangePartType>();
4✔
80

4✔
81
    readonly endPanelMode = input<ThyPanelMode>();
4✔
82

4!
83
    readonly value = model<TinyDate>();
4✔
84

4✔
85
    readonly panelModeChange = output<ThyPanelMode>();
86

NEW
87
    readonly headerChange = output<TinyDate>();
×
NEW
88

×
89
    readonly selectDate = output<TinyDate>();
90

91
    readonly dayHover = output<TinyDate>();
92

5✔
93
    prefixCls = 'thy-calendar';
5✔
94

5✔
95
    constructor() {
5✔
96
        effect(() => {
4✔
97
            if (!this.activeDate()) {
4✔
98
                this.activeDate.set(new TinyDate(undefined, this.timeZone()));
99
            }
100
        });
1✔
101
    }
1✔
102

103
    getReadableValue(value: TinyDate) {
104
        return value ? this.dateHelper.format(value.nativeDate, 'yyyy-MM-dd') : '';
UNCOV
105
    }
×
UNCOV
106

×
UNCOV
107
    onSelectDate(date: TinyDate): void {
×
NEW
108
        const value = date instanceof TinyDate ? date : new TinyDate(date, this.timeZone());
×
UNCOV
109
        this.selectDate.emit(value);
×
UNCOV
110
    }
×
111

112
    onChooseMonth(value: TinyDate): void {
NEW
113
        const activeDate = this.activeDate().setMonth(value.getMonth());
×
NEW
114
        const endPanelMode = this.endPanelMode();
×
115

116
        this.activeDate.set(activeDate);
117
        if (endPanelMode === 'month') {
118
            this.value.set(value);
740✔
119
            this.selectDate.emit(value);
456✔
120
        } else {
456✔
121
            this.headerChange.emit(value);
200✔
122
            this.panelModeChange.emit(endPanelMode);
200✔
123
        }
124
    }
125

256✔
126
    onChooseQuarter(value: TinyDate): void {
127
        const activeDate = this.activeDate().setQuarter(value.getQuarter());
128
        const endPanelMode = this.endPanelMode();
129

284✔
130
        this.activeDate.set(activeDate);
131
        if (endPanelMode === 'quarter') {
132
            this.value.set(value);
133
            this.selectDate.emit(value);
976✔
134
        } else {
558✔
135
            this.headerChange.emit(value);
558✔
136
            this.panelModeChange.emit(endPanelMode);
251✔
137
        }
251✔
138
    }
200✔
139

140
    onChooseYear(value: TinyDate): void {
51✔
141
        const activeDate = this.activeDate().setYear(value.getYear());
34✔
142
        const endPanelMode = this.endPanelMode();
143

17✔
144
        this.activeDate.set(activeDate);
13✔
145
        if (endPanelMode === 'year') {
146
            this.value.set(value);
147
            this.selectDate.emit(value);
148
        } else {
307✔
149
            this.headerChange.emit(value);
150
            this.panelModeChange.emit(endPanelMode);
151
        }
152
    }
418✔
153

154
    onChooseDecade(value: TinyDate): void {
155
        const activeDate = this.activeDate().setYear(value.getYear());
1✔
156
        const endPanelMode = this.endPanelMode();
1✔
157

158
        this.activeDate.set(activeDate);
159
        if (endPanelMode === 'decade') {
160
            this.value.set(value);
161
            this.selectDate.emit(value);
162
        } else {
163
            this.headerChange.emit(value);
164
            this.panelModeChange.emit('year');
165
        }
166
    }
167

168
    enablePrevNext(direction: 'prev' | 'next', mode: ThyPanelMode): boolean {
169
        if (this.isRange()) {
170
            const partType = this.partType();
171
            if ((partType === 'left' && direction === 'next') || (partType === 'right' && direction === 'prev')) {
172
                const [headerLeftDate, headerRightDate] = this.rangeActiveDate();
173
                return isAfterMoreThanOneMonth(headerRightDate, headerLeftDate);
174
            } else {
175
                return true;
176
            }
177
        } else {
1✔
178
            return true;
179
        }
180
    }
181

182
    enableSuperPrevNext(direction: 'prev' | 'next', panelMode: ThyPanelMode) {
183
        if (this.isRange()) {
184
            const partType = this.partType();
185
            if ((partType === 'left' && direction === 'next') || (partType === 'right' && direction === 'prev')) {
186
                const [headerLeftDate, headerRightDate] = this.rangeActiveDate();
187
                if (panelMode === 'date') {
188
                    return isAfterMoreThanLessOneYear(headerRightDate, headerLeftDate);
189
                } else if (panelMode === 'month' || panelMode === 'quarter') {
190
                    return isAfterMoreThanOneYear(headerRightDate, headerLeftDate);
191
                } else if (panelMode === 'year') {
192
                    return isAfterMoreThanOneDecade(headerRightDate, headerLeftDate);
193
                }
194
            } else {
195
                return true;
196
            }
197
        } else {
198
            return true;
199
        }
200
    }
201
}
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