@cdevhub/ngx-tw 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +264 -49
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +11 -7
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-alert.mjs +43 -29
- package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs +103 -0
- package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +56 -31
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +61 -35
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +154 -93
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +24 -15
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +408 -215
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +33 -24
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +144 -79
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +99 -47
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +34 -20
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +46 -29
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +195 -110
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +140 -73
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +16 -11
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +393 -149
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +305 -150
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +56 -43
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +51 -33
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +905 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +49 -26
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +133 -74
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +2 -2
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +28 -17
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +37 -21
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +33 -24
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +63 -48
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +622 -0
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +137 -71
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +101 -46
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +57 -30
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +108 -57
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +46 -26
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select.mjs +217 -122
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-separator.mjs +21 -12
- package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +58 -44
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +25 -14
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +155 -79
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +44 -25
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs +29 -16
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -42
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +107 -64
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +113 -47
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +61 -32
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +88 -42
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +266 -118
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +101 -51
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +798 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +11 -7
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +22 -14
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +243 -95
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +149 -82
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +89 -55
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +50 -28
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +1129 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +554 -0
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw.mjs +7 -0
- package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -1
- package/package.json +45 -20
- package/theme/index.css +10 -2
- package/types/cdevhub-ngx-tw-aspect-ratio.d.ts +40 -0
- package/types/cdevhub-ngx-tw-calendar.d.ts +39 -8
- package/types/cdevhub-ngx-tw-command-palette.d.ts +7 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +36 -10
- package/types/cdevhub-ngx-tw-file-upload.d.ts +250 -0
- package/types/cdevhub-ngx-tw-form-field.d.ts +22 -3
- package/types/cdevhub-ngx-tw-icon-lucide.d.ts +21 -3
- package/types/cdevhub-ngx-tw-number-input.d.ts +130 -0
- package/types/cdevhub-ngx-tw-popover.d.ts +8 -0
- package/types/cdevhub-ngx-tw-stepper.d.ts +30 -2
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +8 -0
- package/types/cdevhub-ngx-tw-table.d.ts +30 -1
- package/types/cdevhub-ngx-tw-tabs.d.ts +8 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +217 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +31 -6
- package/types/cdevhub-ngx-tw-transfer.d.ts +330 -0
- package/types/cdevhub-ngx-tw-tree.d.ts +189 -0
- package/types/cdevhub-ngx-tw.d.ts +7 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, ElementRef, viewChild, signal, computed, ChangeDetectionStrategy, Component, input, booleanAttribute, model, output, ViewContainerRef, Injector, DestroyRef, linkedSignal, effect, untracked, afterNextRender, isDevMode, forwardRef } from '@angular/core';
|
|
3
|
-
import {
|
|
3
|
+
import { NgForm, FormGroupDirective, Validators, NgControl, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
4
|
import { Overlay } from '@angular/cdk/overlay';
|
|
5
5
|
import { FocusMonitor, LiveAnnouncer } from '@angular/cdk/a11y';
|
|
6
6
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
7
7
|
import { merge } from 'rxjs';
|
|
8
8
|
import { tv } from 'tailwind-variants';
|
|
9
9
|
import { PickerOverlayCoordinator, TW_ERROR_STATE_MATCHER, timeOfDaySeconds, resolveSelectScrollStrategy, buildSelectLikePositions } from '@cdevhub/ngx-tw/core';
|
|
10
|
-
import { FormFieldControl,
|
|
11
|
-
import { CalendarComponent, provideSingleSelectionStrategy, DATE_ADAPTER } from '@cdevhub/ngx-tw/calendar';
|
|
10
|
+
import { FormFieldControl, TW_FORM_FIELD, TW_FORM_FIELD_CONTROL } from '@cdevhub/ngx-tw/form-field';
|
|
11
|
+
import { CalendarComponent, provideSingleSelectionStrategy, DATE_ADAPTER, calendarValidator } from '@cdevhub/ngx-tw/calendar';
|
|
12
12
|
import { ButtonDirective } from '@cdevhub/ngx-tw/button';
|
|
13
13
|
import { TimePickerComponent } from '@cdevhub/ngx-tw/time-picker';
|
|
14
14
|
|
|
@@ -20,89 +20,127 @@ import { TimePickerComponent } from '@cdevhub/ngx-tw/time-picker';
|
|
|
20
20
|
*/
|
|
21
21
|
class DatePickerOverlayComponent {
|
|
22
22
|
elementRef = inject((ElementRef));
|
|
23
|
-
calendarRef = viewChild('calendar',
|
|
23
|
+
calendarRef = viewChild('calendar', /* @ts-ignore */
|
|
24
|
+
...(ngDevMode ? [{ debugName: "calendarRef" }] : /* istanbul ignore next */ []));
|
|
24
25
|
// ── Config signals set by the parent component ──
|
|
25
26
|
/** @internal */
|
|
26
|
-
size = signal('md',
|
|
27
|
+
size = signal('md', /* @ts-ignore */
|
|
28
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
27
29
|
/** @internal */
|
|
28
|
-
color = signal('primary',
|
|
30
|
+
color = signal('primary', /* @ts-ignore */
|
|
31
|
+
...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
29
32
|
/** @internal */
|
|
30
|
-
minDate = signal(null,
|
|
33
|
+
minDate = signal(null, /* @ts-ignore */
|
|
34
|
+
...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
|
|
31
35
|
/** @internal */
|
|
32
|
-
maxDate = signal(null,
|
|
36
|
+
maxDate = signal(null, /* @ts-ignore */
|
|
37
|
+
...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
|
|
33
38
|
/** @internal */
|
|
34
|
-
dateFilter = signal(null,
|
|
39
|
+
dateFilter = signal(null, /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "dateFilter" }] : /* istanbul ignore next */ []));
|
|
35
41
|
/** @internal */
|
|
36
|
-
startView = signal('day',
|
|
42
|
+
startView = signal('day', /* @ts-ignore */
|
|
43
|
+
...(ngDevMode ? [{ debugName: "startView" }] : /* istanbul ignore next */ []));
|
|
37
44
|
/** @internal */
|
|
38
|
-
startAt = signal(null,
|
|
45
|
+
startAt = signal(null, /* @ts-ignore */
|
|
46
|
+
...(ngDevMode ? [{ debugName: "startAt" }] : /* istanbul ignore next */ []));
|
|
39
47
|
/** @internal Current committed-or-pending value shown as selected in the calendar. */
|
|
40
|
-
pendingValue = signal(null,
|
|
48
|
+
pendingValue = signal(null, /* @ts-ignore */
|
|
49
|
+
...(ngDevMode ? [{ debugName: "pendingValue" }] : /* istanbul ignore next */ []));
|
|
41
50
|
/** @internal */
|
|
42
|
-
showActions = signal(false,
|
|
51
|
+
showActions = signal(false, /* @ts-ignore */
|
|
52
|
+
...(ngDevMode ? [{ debugName: "showActions" }] : /* istanbul ignore next */ []));
|
|
43
53
|
/** @internal */
|
|
44
|
-
todayLabel = signal('Today',
|
|
54
|
+
todayLabel = signal('Today', /* @ts-ignore */
|
|
55
|
+
...(ngDevMode ? [{ debugName: "todayLabel" }] : /* istanbul ignore next */ []));
|
|
45
56
|
/** @internal */
|
|
46
|
-
clearLabel = signal('Clear',
|
|
57
|
+
clearLabel = signal('Clear', /* @ts-ignore */
|
|
58
|
+
...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
|
|
47
59
|
/** @internal */
|
|
48
|
-
cancelLabel = signal('Cancel',
|
|
60
|
+
cancelLabel = signal('Cancel', /* @ts-ignore */
|
|
61
|
+
...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
|
|
49
62
|
/** @internal */
|
|
50
|
-
applyLabel = signal('Apply',
|
|
63
|
+
applyLabel = signal('Apply', /* @ts-ignore */
|
|
64
|
+
...(ngDevMode ? [{ debugName: "applyLabel" }] : /* istanbul ignore next */ []));
|
|
51
65
|
/** @internal */
|
|
52
|
-
dialogId = signal('',
|
|
66
|
+
dialogId = signal('', /* @ts-ignore */
|
|
67
|
+
...(ngDevMode ? [{ debugName: "dialogId" }] : /* istanbul ignore next */ []));
|
|
53
68
|
/** @internal */
|
|
54
|
-
dialogAriaLabel = signal('Choose a date',
|
|
69
|
+
dialogAriaLabel = signal('Choose a date', /* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "dialogAriaLabel" }] : /* istanbul ignore next */ []));
|
|
55
71
|
/** @internal */
|
|
56
|
-
panelClassValue = signal('',
|
|
72
|
+
panelClassValue = signal('', /* @ts-ignore */
|
|
73
|
+
...(ngDevMode ? [{ debugName: "panelClassValue" }] : /* istanbul ignore next */ []));
|
|
57
74
|
/** @internal */
|
|
58
|
-
leaving = signal(false,
|
|
75
|
+
leaving = signal(false, /* @ts-ignore */
|
|
76
|
+
...(ngDevMode ? [{ debugName: "leaving" }] : /* istanbul ignore next */ []));
|
|
59
77
|
/** @internal Forwarded to the calendar — per-cell CSS classes. */
|
|
60
|
-
dateClass = signal(null,
|
|
78
|
+
dateClass = signal(null, /* @ts-ignore */
|
|
79
|
+
...(ngDevMode ? [{ debugName: "dateClass" }] : /* istanbul ignore next */ []));
|
|
61
80
|
/** @internal Forwarded to the calendar — cell-content template. */
|
|
62
|
-
cellTemplate = signal(null,
|
|
81
|
+
cellTemplate = signal(null, /* @ts-ignore */
|
|
82
|
+
...(ngDevMode ? [{ debugName: "cellTemplate" }] : /* istanbul ignore next */ []));
|
|
63
83
|
/** @internal Forwarded to the calendar — per-instance locale override. */
|
|
64
|
-
locale = signal(null,
|
|
84
|
+
locale = signal(null, /* @ts-ignore */
|
|
85
|
+
...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
65
86
|
/** @internal Quick-select presets rendered above the calendar. */
|
|
66
|
-
presets = signal([],
|
|
87
|
+
presets = signal([], /* @ts-ignore */
|
|
88
|
+
...(ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []));
|
|
67
89
|
// ── Time-picker config ──
|
|
68
90
|
/** @internal */
|
|
69
|
-
withTime = signal(false,
|
|
91
|
+
withTime = signal(false, /* @ts-ignore */
|
|
92
|
+
...(ngDevMode ? [{ debugName: "withTime" }] : /* istanbul ignore next */ []));
|
|
70
93
|
/** @internal */
|
|
71
|
-
timeFormat = signal('24h',
|
|
94
|
+
timeFormat = signal('24h', /* @ts-ignore */
|
|
95
|
+
...(ngDevMode ? [{ debugName: "timeFormat" }] : /* istanbul ignore next */ []));
|
|
72
96
|
/** @internal */
|
|
73
|
-
showSeconds = signal(false,
|
|
97
|
+
showSeconds = signal(false, /* @ts-ignore */
|
|
98
|
+
...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
|
|
74
99
|
/** @internal */
|
|
75
|
-
hourStep = signal(1,
|
|
100
|
+
hourStep = signal(1, /* @ts-ignore */
|
|
101
|
+
...(ngDevMode ? [{ debugName: "hourStep" }] : /* istanbul ignore next */ []));
|
|
76
102
|
/** @internal */
|
|
77
|
-
minuteStep = signal(1,
|
|
103
|
+
minuteStep = signal(1, /* @ts-ignore */
|
|
104
|
+
...(ngDevMode ? [{ debugName: "minuteStep" }] : /* istanbul ignore next */ []));
|
|
78
105
|
/** @internal */
|
|
79
|
-
secondStep = signal(1,
|
|
106
|
+
secondStep = signal(1, /* @ts-ignore */
|
|
107
|
+
...(ngDevMode ? [{ debugName: "secondStep" }] : /* istanbul ignore next */ []));
|
|
80
108
|
/** @internal */
|
|
81
|
-
minTime = signal(null,
|
|
109
|
+
minTime = signal(null, /* @ts-ignore */
|
|
110
|
+
...(ngDevMode ? [{ debugName: "minTime" }] : /* istanbul ignore next */ []));
|
|
82
111
|
/** @internal */
|
|
83
|
-
maxTime = signal(null,
|
|
112
|
+
maxTime = signal(null, /* @ts-ignore */
|
|
113
|
+
...(ngDevMode ? [{ debugName: "maxTime" }] : /* istanbul ignore next */ []));
|
|
84
114
|
// ── Callbacks set by the parent component ──
|
|
85
115
|
/** @internal */
|
|
86
|
-
onCalendarSelect = signal(() => { },
|
|
116
|
+
onCalendarSelect = signal(() => { }, /* @ts-ignore */
|
|
117
|
+
...(ngDevMode ? [{ debugName: "onCalendarSelect" }] : /* istanbul ignore next */ []));
|
|
87
118
|
/** @internal Fires whenever the embedded time-picker commits a new time. */
|
|
88
|
-
onTimeInput = signal(() => { },
|
|
119
|
+
onTimeInput = signal(() => { }, /* @ts-ignore */
|
|
120
|
+
...(ngDevMode ? [{ debugName: "onTimeInput" }] : /* istanbul ignore next */ []));
|
|
89
121
|
/** @internal */
|
|
90
|
-
onToday = signal(() => { },
|
|
122
|
+
onToday = signal(() => { }, /* @ts-ignore */
|
|
123
|
+
...(ngDevMode ? [{ debugName: "onToday" }] : /* istanbul ignore next */ []));
|
|
91
124
|
/** @internal */
|
|
92
|
-
onClear = signal(() => { },
|
|
125
|
+
onClear = signal(() => { }, /* @ts-ignore */
|
|
126
|
+
...(ngDevMode ? [{ debugName: "onClear" }] : /* istanbul ignore next */ []));
|
|
93
127
|
/** @internal */
|
|
94
|
-
onCancel = signal(() => { },
|
|
128
|
+
onCancel = signal(() => { }, /* @ts-ignore */
|
|
129
|
+
...(ngDevMode ? [{ debugName: "onCancel" }] : /* istanbul ignore next */ []));
|
|
95
130
|
/** @internal */
|
|
96
|
-
onApply = signal(() => { },
|
|
131
|
+
onApply = signal(() => { }, /* @ts-ignore */
|
|
132
|
+
...(ngDevMode ? [{ debugName: "onApply" }] : /* istanbul ignore next */ []));
|
|
97
133
|
/** @internal */
|
|
98
|
-
onPresetSelect = signal(() => { },
|
|
134
|
+
onPresetSelect = signal(() => { }, /* @ts-ignore */
|
|
135
|
+
...(ngDevMode ? [{ debugName: "onPresetSelect" }] : /* istanbul ignore next */ []));
|
|
99
136
|
// ── Classes ──
|
|
100
137
|
/** @internal */
|
|
101
138
|
panelClasses = computed(() => {
|
|
102
139
|
const base = 'block bg-surface-overlay border border-border rounded-lg shadow-md overflow-hidden flex flex-col';
|
|
103
140
|
const custom = this.panelClassValue();
|
|
104
141
|
return custom ? `${base} ${custom}` : base;
|
|
105
|
-
},
|
|
142
|
+
}, /* @ts-ignore */
|
|
143
|
+
...(ngDevMode ? [{ debugName: "panelClasses" }] : /* istanbul ignore next */ []));
|
|
106
144
|
// ── Template callbacks ──
|
|
107
145
|
/** @internal */
|
|
108
146
|
onCalendarDateSelected(value) {
|
|
@@ -151,7 +189,8 @@ class DatePickerOverlayComponent {
|
|
|
151
189
|
return !!preset.id && this.activePresetId() === preset.id;
|
|
152
190
|
}
|
|
153
191
|
/** @internal Tracks the most recently picked preset for visual state. Set by the parent. */
|
|
154
|
-
activePresetId = signal(undefined,
|
|
192
|
+
activePresetId = signal(undefined, /* @ts-ignore */
|
|
193
|
+
...(ngDevMode ? [{ debugName: "activePresetId" }] : /* istanbul ignore next */ []));
|
|
155
194
|
/** @internal Moves focus to the active calendar cell. Called by the parent after open. */
|
|
156
195
|
focusCalendar() {
|
|
157
196
|
this.calendarRef()?.focusActiveCell();
|
|
@@ -160,8 +199,8 @@ class DatePickerOverlayComponent {
|
|
|
160
199
|
getElement() {
|
|
161
200
|
return this.elementRef.nativeElement;
|
|
162
201
|
}
|
|
163
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
164
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
202
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: DatePickerOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
203
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: DatePickerOverlayComponent, isStandalone: true, selector: "tw-date-picker-overlay", host: { properties: { "class": "panelClasses()", "id": "dialogId()", "attr.role": "\"dialog\"", "attr.aria-modal": "\"true\"", "attr.aria-label": "dialogAriaLabel()", "animate.enter": "\"scale-in\"", "animate.leave": "leaving() ? \"scale-out\" : \"\"" } }, providers: [provideSingleSelectionStrategy()], viewQueries: [{ propertyName: "calendarRef", first: true, predicate: ["calendar"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
165
204
|
@if (presets().length) {
|
|
166
205
|
<div
|
|
167
206
|
class="flex flex-col gap-1 p-2 border-b border-border bg-surface-muted"
|
|
@@ -246,9 +285,9 @@ class DatePickerOverlayComponent {
|
|
|
246
285
|
</div>
|
|
247
286
|
</div>
|
|
248
287
|
}
|
|
249
|
-
`, isInline: true, dependencies: [{ kind: "component", type: CalendarComponent, selector: "tw-calendar", inputs: ["mode", "value", "startAt", "minDate", "maxDate", "dateFilter", "disabledDates", "disabledDaysOfWeek", "constraints", "minRangeLength", "maxRangeLength", "maxSelections", "maxSelectionBehavior", "errorAriaDescribedBy", "rangeClickBehavior", "rangeBehavior", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "disabled", "readonly", "resetBehavior", "cellTemplate", "locale", "intl"], outputs: ["
|
|
288
|
+
`, isInline: true, dependencies: [{ kind: "component", type: CalendarComponent, selector: "tw-calendar", inputs: ["mode", "value", "startAt", "minDate", "maxDate", "dateFilter", "disabledDates", "disabledDaysOfWeek", "constraints", "minRangeLength", "maxRangeLength", "maxSelections", "maxSelectionBehavior", "errorAriaDescribedBy", "rangeClickBehavior", "rangeBehavior", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "disabled", "readonly", "resetBehavior", "cellTemplate", "locale", "intl"], outputs: ["valueChange", "selectionStart", "rangePreview", "selectionComplete", "selectionRestart", "selectionCleared", "selectionLimitReached", "presetChange", "viewChange", "activeDateChange", "monthChange", "yearChange", "cellClick", "cellHover", "modeChange"] }, { kind: "component", type: TimePickerComponent, selector: "tw-time-picker", inputs: ["id", "disabled", "required", "readonly", "size", "color", "variant", "format", "showSeconds", "hourStep", "minuteStep", "secondStep", "minTime", "maxTime", "referenceDate", "placeholder", "showSteppers", "showClear", "clearLabel", "errorStateMatcher", "aria-label", "aria-labelledby", "aria-describedby", "value"], outputs: ["valueChange", "timeInput", "timeChange"] }, { kind: "directive", type: ButtonDirective, selector: "[twButton]", inputs: ["variant", "color", "size", "disabled", "loading"], exportAs: ["twButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
250
289
|
}
|
|
251
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
290
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: DatePickerOverlayComponent, decorators: [{
|
|
252
291
|
type: Component,
|
|
253
292
|
args: [{
|
|
254
293
|
selector: 'tw-date-picker-overlay',
|
|
@@ -466,22 +505,30 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
466
505
|
// ── Inputs ──
|
|
467
506
|
/** Id on the date-picker's input element. Auto-generated when not provided. Used by the form-field's `<label for>` attribute. */
|
|
468
507
|
idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
|
|
469
|
-
/** Minimum selectable date. Typed input earlier than this
|
|
470
|
-
minDate = input(null,
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
508
|
+
/** Minimum selectable date. Typed input earlier than this commits the value and marks the bound control invalid with `calendarMinDate`; the calendar disables the cell. Defaults to `null`. */
|
|
509
|
+
minDate = input(null, /* @ts-ignore */
|
|
510
|
+
...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
|
|
511
|
+
/** Maximum selectable date. Typed input later than this commits the value and marks the bound control invalid with `calendarMaxDate`; the calendar disables the cell. Defaults to `null`. */
|
|
512
|
+
maxDate = input(null, /* @ts-ignore */
|
|
513
|
+
...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
|
|
514
|
+
/** Per-date predicate — return `false` to disable. Applied in the calendar, the text-parse path, and the `calendarDisabledDate` validation error. */
|
|
515
|
+
dateFilter = input(null, /* @ts-ignore */
|
|
516
|
+
...(ngDevMode ? [{ debugName: "dateFilter" }] : /* istanbul ignore next */ []));
|
|
475
517
|
/** Which calendar view opens first — `'day'`, `'month'`, or `'year'`. Defaults to `'day'`. */
|
|
476
|
-
startView = input('day',
|
|
518
|
+
startView = input('day', /* @ts-ignore */
|
|
519
|
+
...(ngDevMode ? [{ debugName: "startView" }] : /* istanbul ignore next */ []));
|
|
477
520
|
/** Date to focus when the calendar opens with no selection. Falls back to today. */
|
|
478
|
-
startAt = input(null,
|
|
521
|
+
startAt = input(null, /* @ts-ignore */
|
|
522
|
+
...(ngDevMode ? [{ debugName: "startAt" }] : /* istanbul ignore next */ []));
|
|
479
523
|
/** Display format passed to `DateAdapter.format()`. With the default adapter, accepts `{ dateTimeFormat: Intl.DateTimeFormatOptions }`. When `withTime` is true and this is left at the default, hour/minute (and optional seconds) are folded in automatically. */
|
|
480
|
-
format = input(DEFAULT_DISPLAY_FORMAT,
|
|
524
|
+
format = input(DEFAULT_DISPLAY_FORMAT, /* @ts-ignore */
|
|
525
|
+
...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
|
|
481
526
|
/** Optional format hint passed to `DateAdapter.parse()`. Ignored by the native adapter. */
|
|
482
|
-
parseFormat = input(undefined,
|
|
527
|
+
parseFormat = input(undefined, /* @ts-ignore */
|
|
528
|
+
...(ngDevMode ? [{ debugName: "parseFormat" }] : /* istanbul ignore next */ []));
|
|
483
529
|
/** Placeholder text shown in the input when no value is entered. */
|
|
484
|
-
placeholder = input(undefined,
|
|
530
|
+
placeholder = input(undefined, /* @ts-ignore */
|
|
531
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
485
532
|
/** When true, the input is disabled, the trigger cannot open the calendar, and `aria-disabled="true"` is set. Defaults to `false`. */
|
|
486
533
|
disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
|
|
487
534
|
transform: booleanAttribute });
|
|
@@ -492,50 +539,70 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
492
539
|
readonlyInput = input(false, { ...(ngDevMode ? { debugName: "readonlyInput" } : /* istanbul ignore next */ {}), alias: 'readonly',
|
|
493
540
|
transform: booleanAttribute });
|
|
494
541
|
/** Trigger padding, font size, and calendar cell density. Defaults to `'md'`. */
|
|
495
|
-
size = input('md',
|
|
542
|
+
size = input('md', /* @ts-ignore */
|
|
543
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
496
544
|
/** Semantic color for focused border, calendar selection ring, and today marker. Defaults to `'primary'`. */
|
|
497
|
-
color = input('primary',
|
|
545
|
+
color = input('primary', /* @ts-ignore */
|
|
546
|
+
...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
498
547
|
/** Visual style of the trigger. `'default'` draws its own border; `'naked'` strips chrome. Auto-resolves to `'naked'` when inside `<tw-form-field>`. */
|
|
499
|
-
variant = input(undefined,
|
|
548
|
+
variant = input(undefined, /* @ts-ignore */
|
|
549
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
500
550
|
/** Whether to show a clear-button affordance inside the trigger when a value is set. Defaults to `true`. */
|
|
501
551
|
// TRUE-default: a picker without a clear affordance forces consumers to wire one — most form pickers expect the inline clear, matching `<tw-input>`'s clear button.
|
|
502
|
-
showClear = input(true,
|
|
552
|
+
showClear = input(true, /* @ts-ignore */
|
|
553
|
+
...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
|
|
503
554
|
/** When true, renders a `Today / Clear / Cancel / Apply` action bar at the bottom of the overlay. Defaults to `false`. */
|
|
504
|
-
showActions = input(false,
|
|
555
|
+
showActions = input(false, /* @ts-ignore */
|
|
556
|
+
...(ngDevMode ? [{ debugName: "showActions" }] : /* istanbul ignore next */ []));
|
|
505
557
|
/** Label for the `Today` action in the overlay's action bar. */
|
|
506
|
-
todayLabel = input('Today',
|
|
558
|
+
todayLabel = input('Today', /* @ts-ignore */
|
|
559
|
+
...(ngDevMode ? [{ debugName: "todayLabel" }] : /* istanbul ignore next */ []));
|
|
507
560
|
/** Label for the `Clear` action in the overlay's action bar. */
|
|
508
|
-
clearLabel = input('Clear',
|
|
561
|
+
clearLabel = input('Clear', /* @ts-ignore */
|
|
562
|
+
...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
|
|
509
563
|
/** Label for the `Cancel` action in the overlay's action bar. */
|
|
510
|
-
cancelLabel = input('Cancel',
|
|
564
|
+
cancelLabel = input('Cancel', /* @ts-ignore */
|
|
565
|
+
...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
|
|
511
566
|
/** Label for the `Apply` action in the overlay's action bar. */
|
|
512
|
-
applyLabel = input('Apply',
|
|
567
|
+
applyLabel = input('Apply', /* @ts-ignore */
|
|
568
|
+
...(ngDevMode ? [{ debugName: "applyLabel" }] : /* istanbul ignore next */ []));
|
|
513
569
|
/** When true, focusing the text input opens the overlay. Defaults to `false`. */
|
|
514
|
-
openOnFocus = input(false,
|
|
570
|
+
openOnFocus = input(false, /* @ts-ignore */
|
|
571
|
+
...(ngDevMode ? [{ debugName: "openOnFocus" }] : /* istanbul ignore next */ []));
|
|
515
572
|
/** Extra class(es) applied to the overlay panel element. */
|
|
516
|
-
panelClass = input('',
|
|
573
|
+
panelClass = input('', /* @ts-ignore */
|
|
574
|
+
...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
|
|
517
575
|
/** CDK scroll strategy for the overlay. Defaults to `'reposition'`. */
|
|
518
|
-
scrollStrategy = input('reposition',
|
|
576
|
+
scrollStrategy = input('reposition', /* @ts-ignore */
|
|
577
|
+
...(ngDevMode ? [{ debugName: "scrollStrategy" }] : /* istanbul ignore next */ []));
|
|
519
578
|
/** Pixel distance between trigger and overlay. Defaults to `4`. */
|
|
520
|
-
offset = input(4,
|
|
579
|
+
offset = input(4, /* @ts-ignore */
|
|
580
|
+
...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
|
|
521
581
|
/** Accessible name for the calendar trigger button. Defaults to `'Open calendar'`. */
|
|
522
|
-
triggerAriaLabel = input('Open calendar',
|
|
582
|
+
triggerAriaLabel = input('Open calendar', /* @ts-ignore */
|
|
583
|
+
...(ngDevMode ? [{ debugName: "triggerAriaLabel" }] : /* istanbul ignore next */ []));
|
|
523
584
|
/**
|
|
524
585
|
* Bundles the time-of-day configuration. Passing a non-null object turns on the embedded `<tw-time-picker>` and forwards each field.
|
|
525
586
|
*
|
|
526
587
|
* Defaults to `null` (no time field). Pass an empty object `{}` to enable the time picker with all defaults.
|
|
527
588
|
*/
|
|
528
|
-
timeConfig = input(null,
|
|
589
|
+
timeConfig = input(null, /* @ts-ignore */
|
|
590
|
+
...(ngDevMode ? [{ debugName: "timeConfig" }] : /* istanbul ignore next */ []));
|
|
529
591
|
/** Per-instance locale override. Forwarded to the embedded calendar and the underlying `DateAdapter` for parse/format. Falls back to Angular `LOCALE_ID` when `null`. */
|
|
530
|
-
locale = input(null,
|
|
592
|
+
locale = input(null, /* @ts-ignore */
|
|
593
|
+
...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
531
594
|
/** Function producing per-cell CSS classes, forwarded to the embedded calendar. Useful for visually marking special dates (holidays, billing cycles). */
|
|
532
|
-
dateClass = input(null,
|
|
595
|
+
dateClass = input(null, /* @ts-ignore */
|
|
596
|
+
...(ngDevMode ? [{ debugName: "dateClass" }] : /* istanbul ignore next */ []));
|
|
533
597
|
/** Optional cell-content template, forwarded to the embedded calendar. Use to customize cell visuals beyond `dateClass`. */
|
|
534
|
-
cellTemplate = input(null,
|
|
598
|
+
cellTemplate = input(null, /* @ts-ignore */
|
|
599
|
+
...(ngDevMode ? [{ debugName: "cellTemplate" }] : /* istanbul ignore next */ []));
|
|
535
600
|
/** Optional quick-select presets rendered as a vertical list before the calendar. Each preset provides a `label` and a `date` factory. An empty array hides the preset panel. */
|
|
536
|
-
presets = input([],
|
|
601
|
+
presets = input([], /* @ts-ignore */
|
|
602
|
+
...(ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []));
|
|
537
603
|
/** Per-instance override of the `ErrorStateMatcher`. */
|
|
538
|
-
errorStateMatcher = input(undefined,
|
|
604
|
+
errorStateMatcher = input(undefined, /* @ts-ignore */
|
|
605
|
+
...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : /* istanbul ignore next */ []));
|
|
539
606
|
/** Accessible name for the input. Required when no visible label is supplied. Alias: `aria-label`. */
|
|
540
607
|
ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
|
|
541
608
|
/** ID of an external element that labels the input. Alias: `aria-labelledby`. */
|
|
@@ -544,9 +611,11 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
544
611
|
userAriaDescribedByInput = input(undefined, { ...(ngDevMode ? { debugName: "userAriaDescribedByInput" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
545
612
|
// ── Models (two-way) ──
|
|
546
613
|
/** Two-way bound selected date. `null` when no selection. Setting programmatically updates the display; does NOT trigger `onChange`. */
|
|
547
|
-
value = model(null,
|
|
614
|
+
value = model(null, /* @ts-ignore */
|
|
615
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
548
616
|
/** Two-way bound open state of the calendar overlay. */
|
|
549
|
-
open = model(false,
|
|
617
|
+
open = model(false, /* @ts-ignore */
|
|
618
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
550
619
|
// ── Outputs ──
|
|
551
620
|
/** Fires after the overlay's enter animation completes. Payload is the trigger element. */
|
|
552
621
|
opened = output();
|
|
@@ -568,16 +637,24 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
568
637
|
viewContainerRef = inject(ViewContainerRef);
|
|
569
638
|
injector = inject(Injector);
|
|
570
639
|
destroyRef = inject(DestroyRef);
|
|
571
|
-
formField = inject(
|
|
572
|
-
|
|
640
|
+
formField = inject(TW_FORM_FIELD, { optional: true });
|
|
641
|
+
// Resolved lazily in `ngOnInit`, not via eager `inject(NgControl, { self })`:
|
|
642
|
+
// this component provides NG_VALIDATORS with `useExisting`, so NgModel /
|
|
643
|
+
// FormControlName pulling the validator set during construction would resolve
|
|
644
|
+
// back into this instance while it is still being created. Mirrors
|
|
645
|
+
// `date-range-picker.ts` and `calendar.ts`.
|
|
646
|
+
ngControl = null;
|
|
573
647
|
parentForm = inject(NgForm, { optional: true });
|
|
574
648
|
parentFormGroup = inject(FormGroupDirective, { optional: true });
|
|
575
649
|
defaultMatcher = inject(TW_ERROR_STATE_MATCHER);
|
|
576
650
|
// ── View refs ──
|
|
577
|
-
inputRef = viewChild.required('dateInput'
|
|
578
|
-
|
|
651
|
+
inputRef = viewChild.required('dateInput', /* @ts-ignore */
|
|
652
|
+
...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
|
|
653
|
+
triggerRef = viewChild('triggerBtn', /* @ts-ignore */
|
|
654
|
+
...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
|
|
579
655
|
/** @internal Whether a `[slot=trigger]` is projected. Detected post-mount via DOM query so we can drop the default chrome. */
|
|
580
|
-
hasCustomTrigger = signal(false,
|
|
656
|
+
hasCustomTrigger = signal(false, /* @ts-ignore */
|
|
657
|
+
...(ngDevMode ? [{ debugName: "hasCustomTrigger" }] : /* istanbul ignore next */ []));
|
|
581
658
|
// ── Identity ──
|
|
582
659
|
uid = nextDatePickerId++;
|
|
583
660
|
/** @internal */
|
|
@@ -586,26 +663,65 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
586
663
|
dialogId = `${this.hostId}-dialog`;
|
|
587
664
|
// ── Internal state ──
|
|
588
665
|
/** @internal Decouples programmatic writes from user commits so `writeValue` doesn't re-trigger parent effects. */
|
|
589
|
-
internalValue = linkedSignal(() => this.value(),
|
|
666
|
+
internalValue = linkedSignal(() => this.value(), /* @ts-ignore */
|
|
667
|
+
...(ngDevMode ? [{ debugName: "internalValue" }] : /* istanbul ignore next */ []));
|
|
590
668
|
/** @internal */
|
|
591
|
-
rawInputText = signal('',
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
669
|
+
rawInputText = signal('', /* @ts-ignore */
|
|
670
|
+
...(ngDevMode ? [{ debugName: "rawInputText" }] : /* istanbul ignore next */ []));
|
|
671
|
+
/**
|
|
672
|
+
* @internal The text the user typed that could not be parsed into a date,
|
|
673
|
+
* or `null` when the current entry parsed cleanly.
|
|
674
|
+
*
|
|
675
|
+
* This is the single source of truth for "the typed text is bad". It drives
|
|
676
|
+
* both the visual error state (via `parseError` below) and the form error
|
|
677
|
+
* (via `validate()`, which feeds it to `calendarValidator` as
|
|
678
|
+
* `lastInvalidFormValue`). Keeping one field instead of a boolean flag plus a
|
|
679
|
+
* separate string is what stops the two from disagreeing.
|
|
680
|
+
*/
|
|
681
|
+
unparseableText = signal(null, /* @ts-ignore */
|
|
682
|
+
...(ngDevMode ? [{ debugName: "unparseableText" }] : /* istanbul ignore next */ []));
|
|
683
|
+
/** @internal Whether the current input text failed to parse. */
|
|
684
|
+
parseError = computed(() => this.unparseableText() !== null, /* @ts-ignore */
|
|
685
|
+
...(ngDevMode ? [{ debugName: "parseError" }] : /* istanbul ignore next */ []));
|
|
686
|
+
/**
|
|
687
|
+
* @internal Whether the committed value violates `minDate` / `maxDate` /
|
|
688
|
+
* `dateFilter`.
|
|
689
|
+
*
|
|
690
|
+
* Derived, not a flag. An out-of-range entry is committed to the form (so the
|
|
691
|
+
* control holds what the user typed and is *invalid*, rather than silently
|
|
692
|
+
* keeping an older value), which means the value-sync effect below runs and
|
|
693
|
+
* would immediately clear any manually-set flag. Deriving it also keeps the
|
|
694
|
+
* error correct when the consumer moves a constraint after the fact, which a
|
|
695
|
+
* flag set once at commit time cannot do.
|
|
696
|
+
*/
|
|
697
|
+
rangeError = computed(() => {
|
|
698
|
+
const v = this.internalValue();
|
|
699
|
+
return v !== null && !this.isInRange(v);
|
|
700
|
+
}, /* @ts-ignore */
|
|
701
|
+
...(ngDevMode ? [{ debugName: "rangeError" }] : /* istanbul ignore next */ []));
|
|
702
|
+
/** @internal */
|
|
703
|
+
focusedSignal = signal(false, /* @ts-ignore */
|
|
704
|
+
...(ngDevMode ? [{ debugName: "focusedSignal" }] : /* istanbul ignore next */ []));
|
|
705
|
+
cvaDisabled = signal(false, /* @ts-ignore */
|
|
706
|
+
...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
707
|
+
describedByIdsSignal = signal([], /* @ts-ignore */
|
|
708
|
+
...(ngDevMode ? [{ debugName: "describedByIdsSignal" }] : /* istanbul ignore next */ []));
|
|
709
|
+
closingSignal = signal(false, /* @ts-ignore */
|
|
710
|
+
...(ngDevMode ? [{ debugName: "closingSignal" }] : /* istanbul ignore next */ []));
|
|
711
|
+
lastValueBeforeOpen = signal(null, /* @ts-ignore */
|
|
712
|
+
...(ngDevMode ? [{ debugName: "lastValueBeforeOpen" }] : /* istanbul ignore next */ []));
|
|
713
|
+
pendingCalendarValue = signal(null, /* @ts-ignore */
|
|
714
|
+
...(ngDevMode ? [{ debugName: "pendingCalendarValue" }] : /* istanbul ignore next */ []));
|
|
715
|
+
activePresetIdSignal = signal(undefined, /* @ts-ignore */
|
|
716
|
+
...(ngDevMode ? [{ debugName: "activePresetIdSignal" }] : /* istanbul ignore next */ []));
|
|
717
|
+
_ngControlRev = signal(0, /* @ts-ignore */
|
|
718
|
+
...(ngDevMode ? [{ debugName: "_ngControlRev" }] : /* istanbul ignore next */ []));
|
|
719
|
+
_formSubmitRev = signal(0, /* @ts-ignore */
|
|
720
|
+
...(ngDevMode ? [{ debugName: "_formSubmitRev" }] : /* istanbul ignore next */ []));
|
|
606
721
|
onChange = () => { };
|
|
607
722
|
onTouched = () => { };
|
|
608
|
-
overlayInstanceSignal = signal(null,
|
|
723
|
+
overlayInstanceSignal = signal(null, /* @ts-ignore */
|
|
724
|
+
...(ngDevMode ? [{ debugName: "overlayInstanceSignal" }] : /* istanbul ignore next */ []));
|
|
609
725
|
returnFocusTo = null;
|
|
610
726
|
get overlayInstance() {
|
|
611
727
|
return this.overlayInstanceSignal();
|
|
@@ -615,13 +731,17 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
615
731
|
isDisabled = computed(() => {
|
|
616
732
|
this._ngControlRev();
|
|
617
733
|
return this.disabledInput() || this.cvaDisabled() || !!this.ngControl?.disabled;
|
|
618
|
-
},
|
|
734
|
+
}, /* @ts-ignore */
|
|
735
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
619
736
|
/** @internal Effective variant — auto-naked when wrapped in tw-form-field. */
|
|
620
|
-
resolvedVariant = computed(() => this.variant() ?? (this.formField ? 'naked' : 'default'),
|
|
737
|
+
resolvedVariant = computed(() => this.variant() ?? (this.formField ? 'naked' : 'default'), /* @ts-ignore */
|
|
738
|
+
...(ngDevMode ? [{ debugName: "resolvedVariant" }] : /* istanbul ignore next */ []));
|
|
621
739
|
/** @internal */
|
|
622
|
-
isEmpty = computed(() => this.internalValue() === null && !this.rawInputText(),
|
|
740
|
+
isEmpty = computed(() => this.internalValue() === null && !this.rawInputText(), /* @ts-ignore */
|
|
741
|
+
...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
623
742
|
/** Whether the time picker is rendered inside the overlay. True iff `timeConfig` is non-null. */
|
|
624
|
-
withTime = computed(() => this.timeConfig() !== null,
|
|
743
|
+
withTime = computed(() => this.timeConfig() !== null, /* @ts-ignore */
|
|
744
|
+
...(ngDevMode ? [{ debugName: "withTime" }] : /* istanbul ignore next */ []));
|
|
625
745
|
/** @internal Effective time-of-day configuration — merges `timeConfig` over the documented per-field defaults. */
|
|
626
746
|
effectiveTimeConfig = computed(() => {
|
|
627
747
|
const cfg = this.timeConfig();
|
|
@@ -634,7 +754,8 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
634
754
|
minTime: cfg?.minTime ?? null,
|
|
635
755
|
maxTime: cfg?.maxTime ?? null,
|
|
636
756
|
};
|
|
637
|
-
},
|
|
757
|
+
}, /* @ts-ignore */
|
|
758
|
+
...(ngDevMode ? [{ debugName: "effectiveTimeConfig" }] : /* istanbul ignore next */ []));
|
|
638
759
|
/** @internal Effective display format — folds hour/minute (and optional seconds) into the default when `withTime` is on and the user hasn't overridden `format`. */
|
|
639
760
|
effectiveFormat = computed(() => {
|
|
640
761
|
const fmt = this.format();
|
|
@@ -653,7 +774,8 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
653
774
|
if (time.showSeconds)
|
|
654
775
|
base.second = '2-digit';
|
|
655
776
|
return { dateTimeFormat: base };
|
|
656
|
-
},
|
|
777
|
+
}, /* @ts-ignore */
|
|
778
|
+
...(ngDevMode ? [{ debugName: "effectiveFormat" }] : /* istanbul ignore next */ []));
|
|
657
779
|
/** @internal */
|
|
658
780
|
describedBy = computed(() => {
|
|
659
781
|
const extra = this.describedByIdsSignal();
|
|
@@ -666,7 +788,8 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
666
788
|
}
|
|
667
789
|
}
|
|
668
790
|
return merged.length ? merged.join(' ') : '';
|
|
669
|
-
},
|
|
791
|
+
}, /* @ts-ignore */
|
|
792
|
+
...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
670
793
|
// ── tv() output ──
|
|
671
794
|
variantResult = computed(() => datePickerVariants({
|
|
672
795
|
size: this.size(),
|
|
@@ -676,20 +799,27 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
676
799
|
errorState: this.errorState(),
|
|
677
800
|
focused: this.focusedSignal(),
|
|
678
801
|
color: this.color(),
|
|
679
|
-
}),
|
|
802
|
+
}), /* @ts-ignore */
|
|
803
|
+
...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
|
|
680
804
|
/** @internal */
|
|
681
|
-
rootClasses = computed(() => this.variantResult().root(),
|
|
805
|
+
rootClasses = computed(() => this.variantResult().root(), /* @ts-ignore */
|
|
806
|
+
...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
|
|
682
807
|
/** @internal */
|
|
683
|
-
inputClasses = computed(() => this.variantResult().input(),
|
|
808
|
+
inputClasses = computed(() => this.variantResult().input(), /* @ts-ignore */
|
|
809
|
+
...(ngDevMode ? [{ debugName: "inputClasses" }] : /* istanbul ignore next */ []));
|
|
684
810
|
/** @internal */
|
|
685
|
-
triggerButtonClasses = computed(() => this.variantResult().triggerButton(),
|
|
811
|
+
triggerButtonClasses = computed(() => this.variantResult().triggerButton(), /* @ts-ignore */
|
|
812
|
+
...(ngDevMode ? [{ debugName: "triggerButtonClasses" }] : /* istanbul ignore next */ []));
|
|
686
813
|
/** @internal */
|
|
687
|
-
triggerIconClasses = computed(() => this.variantResult().triggerIcon(),
|
|
814
|
+
triggerIconClasses = computed(() => this.variantResult().triggerIcon(), /* @ts-ignore */
|
|
815
|
+
...(ngDevMode ? [{ debugName: "triggerIconClasses" }] : /* istanbul ignore next */ []));
|
|
688
816
|
/** @internal */
|
|
689
|
-
clearButtonClasses = computed(() => this.variantResult().clearButton(),
|
|
817
|
+
clearButtonClasses = computed(() => this.variantResult().clearButton(), /* @ts-ignore */
|
|
818
|
+
...(ngDevMode ? [{ debugName: "clearButtonClasses" }] : /* istanbul ignore next */ []));
|
|
690
819
|
// ── FormFieldControl impl ──
|
|
691
820
|
/** @internal */
|
|
692
|
-
id = computed(() => this.idInput() ?? this.hostId,
|
|
821
|
+
id = computed(() => this.idInput() ?? this.hostId, /* @ts-ignore */
|
|
822
|
+
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
693
823
|
/** @internal */
|
|
694
824
|
focused = this.focusedSignal.asReadonly();
|
|
695
825
|
/** @internal */
|
|
@@ -702,7 +832,8 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
702
832
|
if (this.requiredInput())
|
|
703
833
|
return true;
|
|
704
834
|
return !!this.ngControl?.control?.hasValidator(Validators.required);
|
|
705
|
-
},
|
|
835
|
+
}, /* @ts-ignore */
|
|
836
|
+
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
706
837
|
/** @internal */
|
|
707
838
|
errorState = computed(() => {
|
|
708
839
|
this._ngControlRev();
|
|
@@ -714,29 +845,45 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
714
845
|
const form = this.parentFormGroup ??
|
|
715
846
|
this.parentForm;
|
|
716
847
|
return matcher.isErrorState(this.ngControl?.control ?? null, form);
|
|
717
|
-
},
|
|
848
|
+
}, /* @ts-ignore */
|
|
849
|
+
...(ngDevMode ? [{ debugName: "errorState" }] : /* istanbul ignore next */ []));
|
|
718
850
|
/** @internal */
|
|
719
851
|
controlType = 'date-picker';
|
|
720
852
|
/** @internal */
|
|
721
|
-
userAriaDescribedBy = computed(() => this.userAriaDescribedByInput(),
|
|
853
|
+
userAriaDescribedBy = computed(() => this.userAriaDescribedByInput(), /* @ts-ignore */
|
|
854
|
+
...(ngDevMode ? [{ debugName: "userAriaDescribedBy" }] : /* istanbul ignore next */ []));
|
|
722
855
|
// ── Constructor ──
|
|
723
856
|
constructor() {
|
|
724
857
|
super();
|
|
725
|
-
//
|
|
726
|
-
//
|
|
727
|
-
//
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
858
|
+
// Re-run validation whenever a constraint input changes, so a consumer
|
|
859
|
+
// moving `minDate` after a value was committed updates `control.errors`
|
|
860
|
+
// instead of leaving a stale verdict. `validatorOnChange` is a plain
|
|
861
|
+
// callback into Angular's validator plumbing, not a signal write, so the
|
|
862
|
+
// effect cannot cycle; `untracked` keeps it that way regardless.
|
|
863
|
+
// Mirrors `date-range-picker.ts` and `calendar.ts`.
|
|
864
|
+
effect(() => {
|
|
865
|
+
this.minDate();
|
|
866
|
+
this.maxDate();
|
|
867
|
+
this.dateFilter();
|
|
868
|
+
untracked(() => this.validatorOnChange());
|
|
869
|
+
});
|
|
731
870
|
// Sync rawInputText whenever the underlying value changes (programmatic or user).
|
|
732
871
|
effect(() => {
|
|
733
872
|
const v = this.internalValue();
|
|
734
873
|
const fmt = this.effectiveFormat();
|
|
735
874
|
untracked(() => {
|
|
875
|
+
// An unparseable entry commits `null` precisely *because* it failed to
|
|
876
|
+
// parse, and this effect runs asynchronously afterwards. Syncing here
|
|
877
|
+
// would undo both halves of that: it would clear the error state a
|
|
878
|
+
// moment after it was set, and — because the input is bound to
|
|
879
|
+
// `rawInputText` — blank the very text the user needs to correct,
|
|
880
|
+
// leaving an error border over an empty box. Bail out and let the
|
|
881
|
+
// parse-failure path own the display.
|
|
882
|
+
if (v === null && this.unparseableText() !== null)
|
|
883
|
+
return;
|
|
736
884
|
const display = v === null ? '' : this.adapter.format(v, fmt);
|
|
737
885
|
this.rawInputText.set(display);
|
|
738
|
-
this.
|
|
739
|
-
this.rangeError.set(false);
|
|
886
|
+
this.unparseableText.set(null);
|
|
740
887
|
});
|
|
741
888
|
});
|
|
742
889
|
// Mirror the `open` model into the overlay lifecycle.
|
|
@@ -836,7 +983,7 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
836
983
|
return;
|
|
837
984
|
const hasLabel = !!this.ariaLabel() ||
|
|
838
985
|
!!this.ariaLabelledby() ||
|
|
839
|
-
!!this.formField?.
|
|
986
|
+
!!this.formField?.hasLabel();
|
|
840
987
|
if (!hasLabel) {
|
|
841
988
|
console.warn('[tw-date-picker] The date-picker has no accessible name. Set aria-label, aria-labelledby, or wrap the component in a <tw-form-field> with a <label twLabel>.');
|
|
842
989
|
}
|
|
@@ -861,6 +1008,14 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
861
1008
|
});
|
|
862
1009
|
}
|
|
863
1010
|
ngOnInit() {
|
|
1011
|
+
// Resolve the bound NgControl now that the host's FormControlName / NgModel
|
|
1012
|
+
// is fully constructed (see the field declaration for why this is deferred).
|
|
1013
|
+
// The value accessor itself is registered statically via NG_VALUE_ACCESSOR,
|
|
1014
|
+
// which is what keeps `validate()` on the classic CVA path under v22.
|
|
1015
|
+
this.ngControl = this.injector.get(NgControl, null, { self: true, optional: true });
|
|
1016
|
+
// Anything read off `ngControl` before this point saw `null`; bump the
|
|
1017
|
+
// revision so `isDisabled`, `required` and `errorState` recompute.
|
|
1018
|
+
this._ngControlRev.update((n) => n + 1);
|
|
864
1019
|
const ctrl = this.ngControl?.control;
|
|
865
1020
|
if (ctrl) {
|
|
866
1021
|
const streams = [ctrl.statusChanges, ctrl.valueChanges].filter((s) => !!s);
|
|
@@ -907,8 +1062,7 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
907
1062
|
const target = event.target;
|
|
908
1063
|
const rawText = target.value;
|
|
909
1064
|
this.rawInputText.set(rawText);
|
|
910
|
-
this.
|
|
911
|
-
this.rangeError.set(false);
|
|
1065
|
+
this.unparseableText.set(null);
|
|
912
1066
|
// Non-committing parse so the payload's `parsed` field reflects success when achievable.
|
|
913
1067
|
let parsed = null;
|
|
914
1068
|
if (rawText.trim()) {
|
|
@@ -1036,34 +1190,63 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1036
1190
|
commitFromInput() {
|
|
1037
1191
|
const raw = this.rawInputText().trim();
|
|
1038
1192
|
if (!raw) {
|
|
1193
|
+
this.unparseableText.set(null);
|
|
1039
1194
|
if (this.internalValue() !== null || this.parseError() || this.rangeError()) {
|
|
1040
1195
|
this.commit(null, 'input');
|
|
1041
1196
|
}
|
|
1042
1197
|
else {
|
|
1043
|
-
this.
|
|
1044
|
-
this.rangeError.set(false);
|
|
1198
|
+
this.unparseableText.set(null);
|
|
1045
1199
|
}
|
|
1200
|
+
this.validatorOnChange();
|
|
1046
1201
|
return;
|
|
1047
1202
|
}
|
|
1048
1203
|
const parsed = this.adapter.parse(raw, this.parseFormat());
|
|
1049
1204
|
if (!parsed || !this.adapter.isValid(parsed)) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1205
|
+
// Unparseable. Both halves matter: the previously committed date must not
|
|
1206
|
+
// survive in the form behind an error border (that stale value would be
|
|
1207
|
+
// submitted), and the parse failure must be carried into `validate()`
|
|
1208
|
+
// because the `null` we commit is otherwise indistinguishable from an
|
|
1209
|
+
// empty optional field.
|
|
1210
|
+
// Deliberately not routed through `commit()`: that formats the committed
|
|
1211
|
+
// value into the input, which would erase the text the user just typed.
|
|
1212
|
+
// Clear the *form* value so a stale date cannot be submitted behind an
|
|
1213
|
+
// error border, while leaving the raw text on screen to be corrected.
|
|
1214
|
+
//
|
|
1215
|
+
// Keeping that text visible also depends on the bail-out in the
|
|
1216
|
+
// value-sync effect above — without it, this `internalValue.set(null)`
|
|
1217
|
+
// asynchronously blanks the input. Both halves are pinned by the
|
|
1218
|
+
// "keeps unparseable text visible" specs; changing one without the other
|
|
1219
|
+
// reintroduces an error border over an empty box.
|
|
1220
|
+
const previous = this.internalValue();
|
|
1221
|
+
this.internalValue.set(null);
|
|
1222
|
+
this.value.set(null);
|
|
1223
|
+
this.unparseableText.set(raw);
|
|
1224
|
+
this.onChange(null);
|
|
1225
|
+
this.onTouched();
|
|
1226
|
+
this.validatorOnChange();
|
|
1227
|
+
this.dateChange.emit({ value: null, previousValue: previous, source: 'input' });
|
|
1052
1228
|
return;
|
|
1053
1229
|
}
|
|
1054
1230
|
if (!this.isInRange(parsed)) {
|
|
1055
|
-
|
|
1056
|
-
|
|
1231
|
+
// Out of range still commits: the form should hold what the user actually
|
|
1232
|
+
// entered and be *invalid*, not silently keep an older value. The range
|
|
1233
|
+
// codes come from `validate()` reading `control.value`, so no extra state
|
|
1234
|
+
// needs carrying here.
|
|
1235
|
+
this.unparseableText.set(null);
|
|
1236
|
+
this.commit(parsed, 'input');
|
|
1237
|
+
this.unparseableText.set(null);
|
|
1238
|
+
this.validatorOnChange();
|
|
1057
1239
|
return;
|
|
1058
1240
|
}
|
|
1241
|
+
this.unparseableText.set(null);
|
|
1059
1242
|
this.commit(parsed, 'input');
|
|
1243
|
+
this.validatorOnChange();
|
|
1060
1244
|
}
|
|
1061
1245
|
commit(next, source) {
|
|
1062
1246
|
const previous = this.internalValue();
|
|
1063
1247
|
this.internalValue.set(next);
|
|
1064
1248
|
this.value.set(next);
|
|
1065
|
-
this.
|
|
1066
|
-
this.rangeError.set(false);
|
|
1249
|
+
this.unparseableText.set(null);
|
|
1067
1250
|
const display = next === null ? '' : this.adapter.format(next, this.effectiveFormat());
|
|
1068
1251
|
this.rawInputText.set(display);
|
|
1069
1252
|
const el = this.inputRef().nativeElement;
|
|
@@ -1173,8 +1356,7 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1173
1356
|
this.value.set(previous);
|
|
1174
1357
|
const display = previous === null ? '' : this.adapter.format(previous, this.effectiveFormat());
|
|
1175
1358
|
this.rawInputText.set(display);
|
|
1176
|
-
this.
|
|
1177
|
-
this.rangeError.set(false);
|
|
1359
|
+
this.unparseableText.set(null);
|
|
1178
1360
|
}
|
|
1179
1361
|
}
|
|
1180
1362
|
// Fallback chain ensures focus always returns to a visible element even when
|
|
@@ -1282,8 +1464,7 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1282
1464
|
if (value === null || value === undefined || value === '') {
|
|
1283
1465
|
this.internalValue.set(null);
|
|
1284
1466
|
this.value.set(null);
|
|
1285
|
-
this.
|
|
1286
|
-
this.rangeError.set(false);
|
|
1467
|
+
this.unparseableText.set(null);
|
|
1287
1468
|
this.rawInputText.set('');
|
|
1288
1469
|
this.dateChange.emit({
|
|
1289
1470
|
value: null,
|
|
@@ -1297,20 +1478,18 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1297
1478
|
this.internalValue.set(null);
|
|
1298
1479
|
this.value.set(null);
|
|
1299
1480
|
this.rawInputText.set('');
|
|
1300
|
-
this.
|
|
1301
|
-
this.rangeError.set(false);
|
|
1481
|
+
this.unparseableText.set(null);
|
|
1302
1482
|
return;
|
|
1303
1483
|
}
|
|
1304
1484
|
if (!this.adapter.isValid(coerced)) {
|
|
1305
|
-
this.
|
|
1485
|
+
this.unparseableText.set(String(value));
|
|
1306
1486
|
this.rawInputText.set(String(value));
|
|
1307
1487
|
return;
|
|
1308
1488
|
}
|
|
1309
1489
|
const previous = this.internalValue();
|
|
1310
1490
|
this.internalValue.set(coerced);
|
|
1311
1491
|
this.value.set(coerced);
|
|
1312
|
-
this.
|
|
1313
|
-
this.rangeError.set(false);
|
|
1492
|
+
this.unparseableText.set(null);
|
|
1314
1493
|
this.rawInputText.set(this.adapter.format(coerced, this.effectiveFormat()));
|
|
1315
1494
|
this.dateChange.emit({ value: coerced, previousValue: previous, source: 'programmatic' });
|
|
1316
1495
|
}
|
|
@@ -1323,6 +1502,33 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1323
1502
|
setDisabledState(isDisabled) {
|
|
1324
1503
|
this.cvaDisabled.set(isDisabled);
|
|
1325
1504
|
}
|
|
1505
|
+
// ── Validator ──
|
|
1506
|
+
validatorOnChange = () => { };
|
|
1507
|
+
/** @internal */
|
|
1508
|
+
validate(control) {
|
|
1509
|
+
// Delegate to the shared calendar validator so a `tw-date-picker` reports
|
|
1510
|
+
// the same CalendarErrorCode set as `tw-calendar` and `tw-date-range-picker`
|
|
1511
|
+
// for the same constraint violation.
|
|
1512
|
+
const validator = calendarValidator({
|
|
1513
|
+
mode: 'single',
|
|
1514
|
+
// Carried explicitly rather than inferred from `control.value`: an
|
|
1515
|
+
// unparseable entry commits `null`, and `null` is perfectly valid for a
|
|
1516
|
+
// non-required control, so reading the value alone would report the field
|
|
1517
|
+
// valid while the UI shows an error — the exact bug this fixes.
|
|
1518
|
+
lastInvalidFormValue: this.unparseableText(),
|
|
1519
|
+
constraints: {
|
|
1520
|
+
minDate: this.minDate(),
|
|
1521
|
+
maxDate: this.maxDate(),
|
|
1522
|
+
dateFilter: this.dateFilter(),
|
|
1523
|
+
},
|
|
1524
|
+
adapter: this.adapter,
|
|
1525
|
+
});
|
|
1526
|
+
return validator(control);
|
|
1527
|
+
}
|
|
1528
|
+
/** @internal */
|
|
1529
|
+
registerOnValidatorChange(fn) {
|
|
1530
|
+
this.validatorOnChange = fn;
|
|
1531
|
+
}
|
|
1326
1532
|
// ── FormFieldControl methods ──
|
|
1327
1533
|
/** @internal */
|
|
1328
1534
|
setDescribedByIds(ids) {
|
|
@@ -1342,12 +1548,31 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1342
1548
|
inputEl.focus();
|
|
1343
1549
|
}
|
|
1344
1550
|
}
|
|
1345
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1346
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1551
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1552
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: DatePickerComponent, isStandalone: true, selector: "tw-date-picker", inputs: { idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, parseFormat: { classPropertyName: "parseFormat", publicName: "parseFormat", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, requiredInput: { classPropertyName: "requiredInput", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, readonlyInput: { classPropertyName: "readonlyInput", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: true, isRequired: false, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, applyLabel: { classPropertyName: "applyLabel", publicName: "applyLabel", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, scrollStrategy: { classPropertyName: "scrollStrategy", publicName: "scrollStrategy", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, triggerAriaLabel: { classPropertyName: "triggerAriaLabel", publicName: "triggerAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, timeConfig: { classPropertyName: "timeConfig", publicName: "timeConfig", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, userAriaDescribedByInput: { classPropertyName: "userAriaDescribedByInput", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", open: "openChange", opened: "opened", closed: "closed", dateInput: "dateInput", dateChange: "dateChange", presetSelected: "presetSelected" }, host: { properties: { "class": "rootClasses()" } }, providers: [
|
|
1347
1553
|
{
|
|
1348
1554
|
provide: TW_FORM_FIELD_CONTROL,
|
|
1349
1555
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
1350
1556
|
},
|
|
1557
|
+
{
|
|
1558
|
+
provide: NG_VALIDATORS,
|
|
1559
|
+
useExisting: forwardRef(() => DatePickerComponent),
|
|
1560
|
+
multi: true,
|
|
1561
|
+
},
|
|
1562
|
+
// Angular v22 compiles any component exposing a `value` model() as a
|
|
1563
|
+
// signal-forms custom control, and `FormControlDirective` takes the classic
|
|
1564
|
+
// CVA path — the one that runs `setUpValidators` and composes the
|
|
1565
|
+
// NG_VALIDATORS above onto the control — only if a value accessor is
|
|
1566
|
+
// already visible at directive-creation time. Assigning
|
|
1567
|
+
// `ngControl.valueAccessor` later is too late, so without this static
|
|
1568
|
+
// provider `validate()` is never called and every error code below
|
|
1569
|
+
// disappears silently. See the CVA section of CLAUDE.md; `calendar.ts` and
|
|
1570
|
+
// `date-range-picker.ts` carry the same pair for the same reason.
|
|
1571
|
+
{
|
|
1572
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1573
|
+
useExisting: forwardRef(() => DatePickerComponent),
|
|
1574
|
+
multi: true,
|
|
1575
|
+
},
|
|
1351
1576
|
PickerOverlayCoordinator,
|
|
1352
1577
|
], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["dateInput"], descendants: true, isSignal: true }, { propertyName: "triggerRef", first: true, predicate: ["triggerBtn"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1353
1578
|
<!-- Optional rich-label trigger. When projected (a child carries [slot=trigger]), the default input/clear/trigger chrome is hidden. Clicks anywhere in the projected content open the overlay. -->
|
|
@@ -1442,7 +1667,7 @@ class DatePickerComponent extends FormFieldControl {
|
|
|
1442
1667
|
}
|
|
1443
1668
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1444
1669
|
}
|
|
1445
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1670
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
1446
1671
|
type: Component,
|
|
1447
1672
|
args: [{
|
|
1448
1673
|
selector: 'tw-date-picker',
|
|
@@ -1452,6 +1677,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
1452
1677
|
provide: TW_FORM_FIELD_CONTROL,
|
|
1453
1678
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
1454
1679
|
},
|
|
1680
|
+
{
|
|
1681
|
+
provide: NG_VALIDATORS,
|
|
1682
|
+
useExisting: forwardRef(() => DatePickerComponent),
|
|
1683
|
+
multi: true,
|
|
1684
|
+
},
|
|
1685
|
+
// Angular v22 compiles any component exposing a `value` model() as a
|
|
1686
|
+
// signal-forms custom control, and `FormControlDirective` takes the classic
|
|
1687
|
+
// CVA path — the one that runs `setUpValidators` and composes the
|
|
1688
|
+
// NG_VALIDATORS above onto the control — only if a value accessor is
|
|
1689
|
+
// already visible at directive-creation time. Assigning
|
|
1690
|
+
// `ngControl.valueAccessor` later is too late, so without this static
|
|
1691
|
+
// provider `validate()` is never called and every error code below
|
|
1692
|
+
// disappears silently. See the CVA section of CLAUDE.md; `calendar.ts` and
|
|
1693
|
+
// `date-range-picker.ts` carry the same pair for the same reason.
|
|
1694
|
+
{
|
|
1695
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1696
|
+
useExisting: forwardRef(() => DatePickerComponent),
|
|
1697
|
+
multi: true,
|
|
1698
|
+
},
|
|
1455
1699
|
PickerOverlayCoordinator,
|
|
1456
1700
|
],
|
|
1457
1701
|
template: `
|