forty-cdk 0.2.0 → 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/accordion/README.md +122 -0
- package/aspect-ratio/README.md +76 -0
- package/avatar/README.md +100 -0
- package/breadcrumbs/README.md +49 -0
- package/breakpoints/README.md +81 -0
- package/button/README.md +49 -0
- package/calendar/README.md +458 -0
- package/carousel/README.md +358 -0
- package/checkbox/README.md +146 -0
- package/combobox/README.md +535 -0
- package/context-menu/README.md +139 -0
- package/date-field/README.md +184 -0
- package/date-picker/README.md +338 -0
- package/dialog/README.md +388 -0
- package/disclosure/README.md +114 -0
- package/drag-drop/README.md +359 -0
- package/drawer/README.md +560 -0
- package/dropdown-menu/README.md +176 -0
- package/fesm2022/forty-cdk-accordion.mjs +348 -0
- package/fesm2022/forty-cdk-accordion.mjs.map +1 -0
- package/fesm2022/forty-cdk-aspect-ratio.mjs +74 -0
- package/fesm2022/forty-cdk-aspect-ratio.mjs.map +1 -0
- package/fesm2022/forty-cdk-avatar.mjs +308 -0
- package/fesm2022/forty-cdk-avatar.mjs.map +1 -0
- package/fesm2022/forty-cdk-breadcrumbs.mjs +125 -0
- package/fesm2022/forty-cdk-breadcrumbs.mjs.map +1 -0
- package/fesm2022/forty-cdk-breakpoints.mjs +117 -0
- package/fesm2022/forty-cdk-breakpoints.mjs.map +1 -0
- package/fesm2022/forty-cdk-button.mjs +134 -0
- package/fesm2022/forty-cdk-button.mjs.map +1 -0
- package/fesm2022/forty-cdk-calendar.mjs +2034 -0
- package/fesm2022/forty-cdk-calendar.mjs.map +1 -0
- package/fesm2022/forty-cdk-carousel.mjs +968 -0
- package/fesm2022/forty-cdk-carousel.mjs.map +1 -0
- package/fesm2022/forty-cdk-checkbox.mjs +226 -0
- package/fesm2022/forty-cdk-checkbox.mjs.map +1 -0
- package/fesm2022/forty-cdk-combobox.mjs +2596 -0
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -0
- package/fesm2022/forty-cdk-context-menu.mjs +413 -0
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-core.mjs +9022 -0
- package/fesm2022/forty-cdk-core.mjs.map +1 -0
- package/fesm2022/forty-cdk-date-field.mjs +744 -0
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-date-picker.mjs +1011 -0
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -0
- package/fesm2022/forty-cdk-dialog.mjs +707 -0
- package/fesm2022/forty-cdk-dialog.mjs.map +1 -0
- package/fesm2022/forty-cdk-disclosure.mjs +190 -0
- package/fesm2022/forty-cdk-disclosure.mjs.map +1 -0
- package/fesm2022/forty-cdk-drag-drop.mjs +1180 -0
- package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -0
- package/fesm2022/forty-cdk-drawer.mjs +1641 -0
- package/fesm2022/forty-cdk-drawer.mjs.map +1 -0
- package/fesm2022/forty-cdk-dropdown-menu.mjs +350 -0
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-field.mjs +425 -0
- package/fesm2022/forty-cdk-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-fieldset.mjs +164 -0
- package/fesm2022/forty-cdk-fieldset.mjs.map +1 -0
- package/fesm2022/forty-cdk-file-upload.mjs +221 -0
- package/fesm2022/forty-cdk-file-upload.mjs.map +1 -0
- package/fesm2022/forty-cdk-hover-card.mjs +496 -0
- package/fesm2022/forty-cdk-hover-card.mjs.map +1 -0
- package/fesm2022/forty-cdk-input.mjs +274 -0
- package/fesm2022/forty-cdk-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-internationalized-date.mjs +1 -1
- package/fesm2022/forty-cdk-internationalized-date.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +1279 -0
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -0
- package/fesm2022/forty-cdk-menu.mjs +1439 -0
- package/fesm2022/forty-cdk-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-menubar.mjs +787 -0
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -0
- package/fesm2022/forty-cdk-meter.mjs +211 -0
- package/fesm2022/forty-cdk-meter.mjs.map +1 -0
- package/fesm2022/forty-cdk-navigation-menu.mjs +1145 -0
- package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -0
- package/fesm2022/forty-cdk-number-input.mjs +559 -0
- package/fesm2022/forty-cdk-number-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-otp-input.mjs +527 -0
- package/fesm2022/forty-cdk-otp-input.mjs.map +1 -0
- package/fesm2022/forty-cdk-pagination.mjs +323 -0
- package/fesm2022/forty-cdk-pagination.mjs.map +1 -0
- package/fesm2022/forty-cdk-pane-resizer.mjs +297 -0
- package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -0
- package/fesm2022/forty-cdk-popover.mjs +698 -0
- package/fesm2022/forty-cdk-popover.mjs.map +1 -0
- package/fesm2022/forty-cdk-progress.mjs +226 -0
- package/fesm2022/forty-cdk-progress.mjs.map +1 -0
- package/fesm2022/forty-cdk-radio-group.mjs +378 -0
- package/fesm2022/forty-cdk-radio-group.mjs.map +1 -0
- package/fesm2022/forty-cdk-scroll-area.mjs +640 -0
- package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -0
- package/fesm2022/forty-cdk-search.mjs +205 -0
- package/fesm2022/forty-cdk-search.mjs.map +1 -0
- package/fesm2022/forty-cdk-select.mjs +1661 -0
- package/fesm2022/forty-cdk-select.mjs.map +1 -0
- package/fesm2022/forty-cdk-separator.mjs +82 -0
- package/fesm2022/forty-cdk-separator.mjs.map +1 -0
- package/fesm2022/forty-cdk-signal-forms.mjs +97 -0
- package/fesm2022/forty-cdk-signal-forms.mjs.map +1 -0
- package/fesm2022/forty-cdk-slider.mjs +803 -0
- package/fesm2022/forty-cdk-slider.mjs.map +1 -0
- package/fesm2022/forty-cdk-stepper.mjs +886 -0
- package/fesm2022/forty-cdk-stepper.mjs.map +1 -0
- package/fesm2022/forty-cdk-switch.mjs +137 -0
- package/fesm2022/forty-cdk-switch.mjs.map +1 -0
- package/fesm2022/forty-cdk-table.mjs +1518 -0
- package/fesm2022/forty-cdk-table.mjs.map +1 -0
- package/fesm2022/forty-cdk-tabs.mjs +400 -0
- package/fesm2022/forty-cdk-tabs.mjs.map +1 -0
- package/fesm2022/forty-cdk-time-field.mjs +593 -0
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -0
- package/fesm2022/forty-cdk-time-picker.mjs +1013 -0
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -0
- package/fesm2022/forty-cdk-toast.mjs +1153 -0
- package/fesm2022/forty-cdk-toast.mjs.map +1 -0
- package/fesm2022/forty-cdk-toggle.mjs +516 -0
- package/fesm2022/forty-cdk-toggle.mjs.map +1 -0
- package/fesm2022/forty-cdk-toolbar.mjs +374 -0
- package/fesm2022/forty-cdk-toolbar.mjs.map +1 -0
- package/fesm2022/forty-cdk-tooltip.mjs +672 -0
- package/fesm2022/forty-cdk-tooltip.mjs.map +1 -0
- package/fesm2022/forty-cdk-tree.mjs +2007 -0
- package/fesm2022/forty-cdk-tree.mjs.map +1 -0
- package/fesm2022/forty-cdk-virtualization.mjs +1 -1
- package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
- package/fesm2022/forty-cdk.mjs +0 -43310
- package/fesm2022/forty-cdk.mjs.map +1 -1
- package/field/README.md +97 -0
- package/fieldset/README.md +86 -0
- package/file-upload/README.md +73 -0
- package/hover-card/README.md +171 -0
- package/input/README.md +156 -0
- package/listbox/README.md +424 -0
- package/menu/README.md +181 -0
- package/menubar/README.md +140 -0
- package/meter/README.md +128 -0
- package/navigation-menu/README.md +253 -0
- package/number-input/README.md +171 -0
- package/otp-input/README.md +198 -0
- package/package.json +213 -1
- package/pagination/README.md +61 -0
- package/pane-resizer/README.md +136 -0
- package/popover/README.md +262 -0
- package/progress/README.md +115 -0
- package/radio-group/README.md +129 -0
- package/scroll-area/README.md +184 -0
- package/search/README.md +42 -0
- package/select/README.md +488 -0
- package/separator/README.md +84 -0
- package/signal-forms/README.md +72 -0
- package/slider/README.md +152 -0
- package/stepper/README.md +292 -0
- package/switch/README.md +116 -0
- package/table/README.md +769 -0
- package/tabs/README.md +130 -0
- package/time-field/README.md +157 -0
- package/time-picker/README.md +172 -0
- package/toast/README.md +398 -0
- package/toggle/README.md +224 -0
- package/toolbar/README.md +109 -0
- package/tooltip/README.md +274 -0
- package/tree/README.md +708 -0
- package/types/forty-cdk-accordion.d.ts +242 -0
- package/types/forty-cdk-aspect-ratio.d.ts +59 -0
- package/types/forty-cdk-avatar.d.ts +133 -0
- package/types/forty-cdk-breadcrumbs.d.ts +92 -0
- package/types/forty-cdk-breakpoints.d.ts +141 -0
- package/types/forty-cdk-button.d.ts +80 -0
- package/types/forty-cdk-calendar.d.ts +914 -0
- package/types/forty-cdk-carousel.d.ts +530 -0
- package/types/forty-cdk-checkbox.d.ts +141 -0
- package/types/forty-cdk-combobox.d.ts +1259 -0
- package/types/forty-cdk-context-menu.d.ts +313 -0
- package/types/forty-cdk-core.d.ts +5774 -0
- package/types/forty-cdk-date-field.d.ts +307 -0
- package/types/forty-cdk-date-picker.d.ts +622 -0
- package/types/forty-cdk-dialog.d.ts +546 -0
- package/types/forty-cdk-disclosure.d.ts +127 -0
- package/types/forty-cdk-drag-drop.d.ts +456 -0
- package/types/forty-cdk-drawer.d.ts +871 -0
- package/types/forty-cdk-dropdown-menu.d.ts +242 -0
- package/types/forty-cdk-field.d.ts +236 -0
- package/types/forty-cdk-fieldset.d.ts +119 -0
- package/types/forty-cdk-file-upload.d.ts +124 -0
- package/types/forty-cdk-hover-card.d.ts +320 -0
- package/types/forty-cdk-input.d.ts +169 -0
- package/types/forty-cdk-internationalized-date.d.ts +1 -1
- package/types/forty-cdk-listbox.d.ts +513 -0
- package/types/forty-cdk-menu.d.ts +629 -0
- package/types/forty-cdk-menubar.d.ts +451 -0
- package/types/forty-cdk-meter.d.ts +122 -0
- package/types/forty-cdk-navigation-menu.d.ts +514 -0
- package/types/forty-cdk-number-input.d.ts +319 -0
- package/types/forty-cdk-otp-input.d.ts +248 -0
- package/types/forty-cdk-pagination.d.ts +214 -0
- package/types/forty-cdk-pane-resizer.d.ts +145 -0
- package/types/forty-cdk-popover.d.ts +509 -0
- package/types/forty-cdk-progress.d.ts +143 -0
- package/types/forty-cdk-radio-group.d.ts +222 -0
- package/types/forty-cdk-scroll-area.d.ts +258 -0
- package/types/forty-cdk-search.d.ts +142 -0
- package/types/forty-cdk-select.d.ts +899 -0
- package/types/forty-cdk-separator.d.ts +59 -0
- package/types/forty-cdk-signal-forms.d.ts +58 -0
- package/types/forty-cdk-slider.d.ts +379 -0
- package/types/forty-cdk-stepper.d.ts +650 -0
- package/types/forty-cdk-switch.d.ts +87 -0
- package/types/forty-cdk-table.d.ts +723 -0
- package/types/forty-cdk-tabs.d.ts +235 -0
- package/types/forty-cdk-time-field.d.ts +307 -0
- package/types/forty-cdk-time-picker.d.ts +578 -0
- package/types/forty-cdk-toast.d.ts +598 -0
- package/types/forty-cdk-toggle.d.ts +310 -0
- package/types/forty-cdk-toolbar.d.ts +217 -0
- package/types/forty-cdk-tooltip.d.ts +436 -0
- package/types/forty-cdk-tree.d.ts +688 -0
- package/types/forty-cdk.d.ts +1 -19743
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ElementRef, model, input, computed, linkedSignal, Directive } from '@angular/core';
|
|
3
|
+
import { createDefaults, FormUiControlBase, assertTimeCapable, injectDateAdapter, injectTextDirection, RovingTabindex, resolveHourCycle, dayPeriodNames, SegmentEditor, injectHiddenInput, serializeISOTime, timeSentinel, secondsOfDay, composeWithTime, FOR_TIME_VALUE_SOURCE, ForDateTimeSegmentBase, ForDateTimeLiteralBase } from 'forty-cdk/core';
|
|
4
|
+
|
|
5
|
+
const DIGITS = {
|
|
6
|
+
hour: 2,
|
|
7
|
+
minute: 2,
|
|
8
|
+
second: 2,
|
|
9
|
+
dayPeriod: 0,
|
|
10
|
+
};
|
|
11
|
+
// 1:23:45 PM — distinct hour / minute / second values and a PM reference so the
|
|
12
|
+
// `dayPeriod` part is present to read back. Only each part's `type` (and the
|
|
13
|
+
// separators) are used; the concrete value never surfaces.
|
|
14
|
+
const REFERENCE_TIME = new Date(2000, 0, 1, 13, 23, 45);
|
|
15
|
+
/**
|
|
16
|
+
* Derives the ordered segment list for a time field from the runtime locale,
|
|
17
|
+
* the resolved hour cycle, and the granularity, using
|
|
18
|
+
* `Intl.DateTimeFormat(...).formatToParts`. The visible order of the segments
|
|
19
|
+
* (and the separators between them), and whether an AM/PM `dayPeriod` segment
|
|
20
|
+
* is present, follow the locale and the 12-/24-hour cycle.
|
|
21
|
+
*
|
|
22
|
+
* Pure: the same arguments always yield the same list, touching no signals or
|
|
23
|
+
* DOM.
|
|
24
|
+
*
|
|
25
|
+
* @param locale BCP 47 locale, or `undefined` for the runtime default.
|
|
26
|
+
* @param hourCycle Resolved hour cycle (`12` shows AM/PM, `24` does not).
|
|
27
|
+
* @param granularity Smallest editable unit; trims minute / second segments.
|
|
28
|
+
*/
|
|
29
|
+
function buildTimeSegments(locale, hourCycle, granularity) {
|
|
30
|
+
const options = { hour: '2-digit', hour12: hourCycle === 12 };
|
|
31
|
+
if (granularity !== 'hour') {
|
|
32
|
+
options.minute = '2-digit';
|
|
33
|
+
}
|
|
34
|
+
if (granularity === 'second') {
|
|
35
|
+
options.second = '2-digit';
|
|
36
|
+
}
|
|
37
|
+
const parts = new Intl.DateTimeFormat(locale, options).formatToParts(REFERENCE_TIME);
|
|
38
|
+
const segments = [];
|
|
39
|
+
for (const part of parts) {
|
|
40
|
+
switch (part.type) {
|
|
41
|
+
case 'hour':
|
|
42
|
+
case 'minute':
|
|
43
|
+
case 'second':
|
|
44
|
+
case 'dayPeriod':
|
|
45
|
+
segments.push({ kind: 'editable', type: part.type, digits: DIGITS[part.type] });
|
|
46
|
+
break;
|
|
47
|
+
case 'literal':
|
|
48
|
+
segments.push({ kind: 'literal', literal: part.value });
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return segments;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Injection token for the {@link ForTimeFieldContext} provided by
|
|
59
|
+
* `[forTimeField]`. Segment and literal children inject it to coordinate with
|
|
60
|
+
* the root.
|
|
61
|
+
*/
|
|
62
|
+
const FOR_TIME_FIELD_CONTEXT = new InjectionToken('FOR_TIME_FIELD_CONTEXT');
|
|
63
|
+
/**
|
|
64
|
+
* Resolves the surrounding {@link ForTimeFieldContext}, throwing a descriptive,
|
|
65
|
+
* primitive-prefixed error when used outside a `[forTimeField]`.
|
|
66
|
+
*
|
|
67
|
+
* @param piece Name of the calling directive, used in the error message.
|
|
68
|
+
*/
|
|
69
|
+
function injectTimeFieldContext(piece) {
|
|
70
|
+
const ctx = inject(FOR_TIME_FIELD_CONTEXT, { optional: true });
|
|
71
|
+
if (!ctx) {
|
|
72
|
+
throw new Error(`[forty-cdk/time-field] ${piece} must be used inside a [forTimeField].`);
|
|
73
|
+
}
|
|
74
|
+
return ctx;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Library default accessible name for each editable segment. Used when neither
|
|
79
|
+
* the segment's explicit `ariaLabel` nor a `provideForTimeFieldDefaults`
|
|
80
|
+
* override supplies one for that part.
|
|
81
|
+
*/
|
|
82
|
+
const DEFAULT_TIME_FIELD_SEGMENT_LABELS = {
|
|
83
|
+
hour: 'hour',
|
|
84
|
+
minute: 'minute',
|
|
85
|
+
second: 'second',
|
|
86
|
+
dayPeriod: 'AM/PM',
|
|
87
|
+
};
|
|
88
|
+
const FALLBACK = {
|
|
89
|
+
emptySegmentText: 'Empty',
|
|
90
|
+
segmentLabels: DEFAULT_TIME_FIELD_SEGMENT_LABELS,
|
|
91
|
+
};
|
|
92
|
+
const { token, provideDefaults } = createDefaults('FOR_TIME_FIELD_DEFAULTS', FALLBACK);
|
|
93
|
+
/** Token holding the resolved time-field defaults for the current scope. */
|
|
94
|
+
const FOR_TIME_FIELD_DEFAULTS = token;
|
|
95
|
+
/**
|
|
96
|
+
* Configures forty-cdk time-field defaults for this injector scope. Partial
|
|
97
|
+
* overrides inherit unspecified keys from the parent scope (or library
|
|
98
|
+
* defaults at the root).
|
|
99
|
+
*/
|
|
100
|
+
function provideForTimeFieldDefaults(defaults = {}) {
|
|
101
|
+
return provideDefaults(defaults);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Headless, segmented, spin-editable time-of-day input — the time counterpart
|
|
106
|
+
* to `ForDateField`. There is no single WAI-ARIA APG pattern for a time field;
|
|
107
|
+
* it is a composition of
|
|
108
|
+
* [Spinbuttons](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/) inside a
|
|
109
|
+
* labelled `role="group"`.
|
|
110
|
+
* Each hour / minute / second / AM·PM part is an independent
|
|
111
|
+
* `role="spinbutton"` segment (`[forTimeFieldSegment]`) so entry is unambiguous
|
|
112
|
+
* and locale-correct.
|
|
113
|
+
*
|
|
114
|
+
* `ForTimeField` is the root: it owns the entered parts, composes them into the
|
|
115
|
+
* adapter's date-time type, resolves the locale-ordered segment list, and
|
|
116
|
+
* exposes everything to the segment / literal children through
|
|
117
|
+
* {@link FOR_TIME_FIELD_CONTEXT}. The spin-button engine (digit typing,
|
|
118
|
+
* stepping, Home/End, RTL focus moves, the segment registry) lives in the shared
|
|
119
|
+
* `_internal/datetime` {@link SegmentEditor}; the root supplies only the
|
|
120
|
+
* time-specific bits (segment bounds, the midnight seed, and the
|
|
121
|
+
* sentinel-anchored setTime/clamp compose). All time math goes through the
|
|
122
|
+
* pluggable {@link import('../_internal/date-adapter/date-adapter').DateAdapter} shared with
|
|
123
|
+
* `ForCalendar`, which **must be time-capable** — `provideNativeDateAdapter()`
|
|
124
|
+
* or `provideInternationalizedDateTimeAdapter()` (the day-only
|
|
125
|
+
* `provideInternationalizedDateAdapter()` throws).
|
|
126
|
+
*
|
|
127
|
+
* It implements `FormValueControl<D | null>` from `@angular/forms/signals`, so
|
|
128
|
+
* it auto-wires with `[formField]` and auto-associates inside a `[forField]`.
|
|
129
|
+
* The value stays `null` until every visible segment is filled. When no value
|
|
130
|
+
* is bound yet, the composed value is anchored on a fixed, DST-stable sentinel
|
|
131
|
+
* date (`2000-01-01`) rather than today, so a wall-clock time always round-trips
|
|
132
|
+
* to the same instant; bind an existing date-time as `value` to edit its time in
|
|
133
|
+
* place.
|
|
134
|
+
*
|
|
135
|
+
* @typeParam D The adapter's immutable, time-capable date-time type.
|
|
136
|
+
*
|
|
137
|
+
* Note: the bounds are named `minTime` / `maxTime`, not `min` / `max` — the
|
|
138
|
+
* latter are reserved `FormUiControl` members typed `number | undefined` for
|
|
139
|
+
* numeric validators, so a date-time-typed `min` / `max` would break the
|
|
140
|
+
* `FormValueControl` contract. Only the time-of-day component of the bounds is
|
|
141
|
+
* considered.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```html
|
|
145
|
+
* <div forTimeField [(value)]="time" [hourCycle]="24"
|
|
146
|
+
* [ariaLabel]="'Appointment time'" #field="forTimeField">
|
|
147
|
+
* @for (seg of field.segments(); track seg.id) {
|
|
148
|
+
* @if (seg.isLiteral) {
|
|
149
|
+
* <span forTimeFieldLiteral>{{ seg.text }}</span>
|
|
150
|
+
* } @else {
|
|
151
|
+
* <span forTimeFieldSegment [segment]="seg.type!">{{ seg.text }}</span>
|
|
152
|
+
* }
|
|
153
|
+
* }
|
|
154
|
+
* </div>
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
class ForTimeField extends FormUiControlBase {
|
|
158
|
+
#host = inject(ElementRef);
|
|
159
|
+
#defaults = inject(FOR_TIME_FIELD_DEFAULTS);
|
|
160
|
+
/**
|
|
161
|
+
* The active, time-capable date adapter, resolved from `FOR_DATE_ADAPTER`
|
|
162
|
+
* (shared with `ForCalendar`). Throws when the provided adapter is day-only.
|
|
163
|
+
*/
|
|
164
|
+
adapter = assertTimeCapable(injectDateAdapter('ForTimeField'), 'ForTimeField');
|
|
165
|
+
/**
|
|
166
|
+
* Two-way bindable entered time, or `null` while any visible segment is
|
|
167
|
+
* empty. Required by `FormValueControl<D | null>`. The `model()` change
|
|
168
|
+
* emitter (`(valueChange)`) fires only when the field itself composes a new
|
|
169
|
+
* value, never on consumer writes via `[(value)]`.
|
|
170
|
+
*
|
|
171
|
+
* When no value is bound, the composed date-time anchors its date part on a
|
|
172
|
+
* fixed, DST-stable sentinel date (`2000-01-01`) instead of today. This avoids
|
|
173
|
+
* two `today()` hazards on adapters whose `D` carries a time zone (e.g.
|
|
174
|
+
* `NativeDateAdapter`'s `Date`): a wall-clock time on a DST-transition day that
|
|
175
|
+
* does not exist or is ambiguous would silently shift the emitted instant, and
|
|
176
|
+
* a today-anchored value would leak the current date into a time-only control
|
|
177
|
+
* (so a persisted value re-derives a different time next week). Consumers
|
|
178
|
+
* reading the emitted value should treat only its time-of-day component as
|
|
179
|
+
* meaningful while no date is bound. `CalendarDateTime` (no time zone) is
|
|
180
|
+
* unaffected, but anchors on the same sentinel for consistency.
|
|
181
|
+
*/
|
|
182
|
+
value = model(null, /* @ts-ignore */
|
|
183
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
184
|
+
/**
|
|
185
|
+
* Earliest selectable time-of-day (inclusive). A composed value earlier in
|
|
186
|
+
* the day is clamped up to it. Named `minTime` (not `min`) because
|
|
187
|
+
* `FormUiControl.min` is reserved for a numeric validator. Only the
|
|
188
|
+
* hour / minute / second component is considered.
|
|
189
|
+
*/
|
|
190
|
+
minTime = input(null, /* @ts-ignore */
|
|
191
|
+
...(ngDevMode ? [{ debugName: "minTime" }] : /* istanbul ignore next */ []));
|
|
192
|
+
/**
|
|
193
|
+
* Latest selectable time-of-day (inclusive). A composed value later in the
|
|
194
|
+
* day is clamped down to it. Named `maxTime` for the same reason as
|
|
195
|
+
* {@link minTime}.
|
|
196
|
+
*/
|
|
197
|
+
maxTime = input(null, /* @ts-ignore */
|
|
198
|
+
...(ngDevMode ? [{ debugName: "maxTime" }] : /* istanbul ignore next */ []));
|
|
199
|
+
/**
|
|
200
|
+
* 12- or 24-hour cycle. When `null` (default) it is derived from the runtime
|
|
201
|
+
* locale. A 12-hour cycle adds the AM/PM `dayPeriod` segment.
|
|
202
|
+
*/
|
|
203
|
+
hourCycle = input(null, /* @ts-ignore */
|
|
204
|
+
...(ngDevMode ? [{ debugName: "hourCycle" }] : /* istanbul ignore next */ []));
|
|
205
|
+
/** Smallest editable unit: `'hour'`, `'minute'` (default), or `'second'`. */
|
|
206
|
+
granularity = input('minute', /* @ts-ignore */
|
|
207
|
+
...(ngDevMode ? [{ debugName: "granularity" }] : /* istanbul ignore next */ []));
|
|
208
|
+
/** BCP 47 locale driving segment order, separators, and AM/PM names. Defaults to the runtime locale. */
|
|
209
|
+
locale = input(null, /* @ts-ignore */
|
|
210
|
+
...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
211
|
+
/**
|
|
212
|
+
* Per-segment placeholder shown while empty. Unspecified parts fall back to
|
|
213
|
+
* `hh` / `mm` / `ss` / `--`.
|
|
214
|
+
*/
|
|
215
|
+
placeholder = input({}, /* @ts-ignore */
|
|
216
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
217
|
+
/** Accessible name for the field group. Emits no `aria-label` while `null`. */
|
|
218
|
+
ariaLabel = input(null, /* @ts-ignore */
|
|
219
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
220
|
+
/**
|
|
221
|
+
* Writing direction. When unset (default `null`), the inherited ambient
|
|
222
|
+
* direction is resolved from the nearest ancestor carrying a `dir` attribute
|
|
223
|
+
* (or `<html dir>`), defaulting to `'ltr'`. An explicit `[dir]` always wins.
|
|
224
|
+
* The resolved value is reflected to the host `dir` attribute and mirrors the
|
|
225
|
+
* ArrowLeft / ArrowRight segment navigation in RTL.
|
|
226
|
+
*/
|
|
227
|
+
_dirInput = input(null, { ...(ngDevMode ? { debugName: "_dirInput" } : /* istanbul ignore next */ {}), alias: 'dir' });
|
|
228
|
+
dir = injectTextDirection(this._dirInput);
|
|
229
|
+
/** Shared roving-tabindex tracker: exactly one segment owns `tabindex=0`. */
|
|
230
|
+
roving = new RovingTabindex();
|
|
231
|
+
/** Resolved hour cycle (`12` shows AM/PM, `24` does not). */
|
|
232
|
+
#cycle = computed(() => resolveHourCycle(this.locale() ?? undefined, this.hourCycle()), /* @ts-ignore */
|
|
233
|
+
...(ngDevMode ? [{ debugName: "#cycle" }] : /* istanbul ignore next */ []));
|
|
234
|
+
#specs = computed(() => buildTimeSegments(this.locale() ?? undefined, this.#cycle(), this.granularity()), /* @ts-ignore */
|
|
235
|
+
...(ngDevMode ? [{ debugName: "#specs" }] : /* istanbul ignore next */ []));
|
|
236
|
+
#editableOrder = computed(() => this.#specs()
|
|
237
|
+
.filter((spec) => spec.kind === 'editable')
|
|
238
|
+
.map((spec) => spec.type), /* @ts-ignore */
|
|
239
|
+
...(ngDevMode ? [{ debugName: "#editableOrder" }] : /* istanbul ignore next */ []));
|
|
240
|
+
#periodNames = computed(() => dayPeriodNames(this.locale() ?? undefined), /* @ts-ignore */
|
|
241
|
+
...(ngDevMode ? [{ debugName: "#periodNames" }] : /* istanbul ignore next */ []));
|
|
242
|
+
/**
|
|
243
|
+
* The entered parts. A `linkedSignal` keyed on `value`: a non-null write
|
|
244
|
+
* (consumer, `[formField]`, or our own compose) rehydrates the parts from the
|
|
245
|
+
* date-time. A `null` transition is disambiguated by the prior parts — an
|
|
246
|
+
* internal edit clearing one segment leaves the others, so `previous` still
|
|
247
|
+
* carries a filled part and is preserved; an external reset of a complete
|
|
248
|
+
* value clears the field.
|
|
249
|
+
*/
|
|
250
|
+
#parts = linkedSignal({ ...(ngDevMode ? { debugName: "#parts" } : /* istanbul ignore next */ {}), source: this.value,
|
|
251
|
+
computation: (current, previous) => {
|
|
252
|
+
if (current !== null) {
|
|
253
|
+
return {
|
|
254
|
+
hour: this.adapter.getHours(current),
|
|
255
|
+
minute: this.adapter.getMinutes(current),
|
|
256
|
+
second: this.adapter.getSeconds(current),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const prior = previous?.value;
|
|
260
|
+
if (prior && (prior.hour === null || prior.minute === null || prior.second === null)) {
|
|
261
|
+
return prior;
|
|
262
|
+
}
|
|
263
|
+
return { hour: null, minute: null, second: null };
|
|
264
|
+
} });
|
|
265
|
+
#editor = new SegmentEditor({
|
|
266
|
+
disabled: this.effectiveDisabled,
|
|
267
|
+
readonly: this.readonly,
|
|
268
|
+
roving: this.roving,
|
|
269
|
+
cycle: this.#cycle,
|
|
270
|
+
specs: this.#specs,
|
|
271
|
+
editableOrder: this.#editableOrder,
|
|
272
|
+
periodNames: this.#periodNames,
|
|
273
|
+
parts: () => this.#parts(),
|
|
274
|
+
segmentMin: (type) => this.segmentMin(type),
|
|
275
|
+
segmentMax: (type) => this.segmentMax(type),
|
|
276
|
+
seed: (type) => this.#seed(type),
|
|
277
|
+
placeholderFor: (type) => this.#placeholderFor(type),
|
|
278
|
+
valueText: (type) => this.#valueText(type),
|
|
279
|
+
commit: (next) => this.#commitParts(next),
|
|
280
|
+
});
|
|
281
|
+
/**
|
|
282
|
+
* The ordered, locale-derived segments (editable + literals) to render. Each
|
|
283
|
+
* entry carries the text to display: the formatted value when filled, the
|
|
284
|
+
* placeholder while empty, or the literal separator.
|
|
285
|
+
*/
|
|
286
|
+
segments = this.#editor.segments;
|
|
287
|
+
constructor() {
|
|
288
|
+
super();
|
|
289
|
+
injectHiddenInput({
|
|
290
|
+
name: this.name,
|
|
291
|
+
values: computed(() => {
|
|
292
|
+
const current = this.value();
|
|
293
|
+
if (current === null) {
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
return [serializeISOTime(this.adapter, current, this.granularity())];
|
|
297
|
+
}),
|
|
298
|
+
disabled: this.effectiveDisabled,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
segmentValue(type) {
|
|
302
|
+
return this.#editor.segmentValue(type);
|
|
303
|
+
}
|
|
304
|
+
segmentMin(type) {
|
|
305
|
+
if (type === 'hour') {
|
|
306
|
+
return this.#cycle() === 12 ? 1 : 0;
|
|
307
|
+
}
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
310
|
+
segmentMax(type) {
|
|
311
|
+
if (type === 'hour') {
|
|
312
|
+
return this.#cycle() === 12 ? 12 : 23;
|
|
313
|
+
}
|
|
314
|
+
if (type === 'dayPeriod') {
|
|
315
|
+
return 1;
|
|
316
|
+
}
|
|
317
|
+
return 59;
|
|
318
|
+
}
|
|
319
|
+
segmentValueText(type) {
|
|
320
|
+
return this.#editor.segmentValueText(type);
|
|
321
|
+
}
|
|
322
|
+
segmentDisplayText(type) {
|
|
323
|
+
return this.#editor.segmentDisplayText(type);
|
|
324
|
+
}
|
|
325
|
+
isSegmentEmpty(type) {
|
|
326
|
+
return this.#editor.isSegmentEmpty(type);
|
|
327
|
+
}
|
|
328
|
+
isFirstSegmentType(type) {
|
|
329
|
+
return this.#editor.isFirstSegmentType(type);
|
|
330
|
+
}
|
|
331
|
+
registerSegment(handle) {
|
|
332
|
+
this.#editor.registerSegment(handle);
|
|
333
|
+
}
|
|
334
|
+
unregisterSegment(handle) {
|
|
335
|
+
this.#editor.unregisterSegment(handle);
|
|
336
|
+
}
|
|
337
|
+
focusSegment(type) {
|
|
338
|
+
this.#editor.focusSegment(type);
|
|
339
|
+
}
|
|
340
|
+
typeDigit(type, digit) {
|
|
341
|
+
this.#editor.typeDigit(type, digit);
|
|
342
|
+
}
|
|
343
|
+
step(type, delta) {
|
|
344
|
+
this.#editor.step(type, delta);
|
|
345
|
+
}
|
|
346
|
+
goToBound(type, bound) {
|
|
347
|
+
this.#editor.goToBound(type, bound);
|
|
348
|
+
}
|
|
349
|
+
setDayPeriod(period) {
|
|
350
|
+
this.#editor.setDayPeriod(period);
|
|
351
|
+
}
|
|
352
|
+
clear(type) {
|
|
353
|
+
this.#editor.clear(type);
|
|
354
|
+
}
|
|
355
|
+
focusSibling(type, step) {
|
|
356
|
+
this.#editor.focusSibling(type, step);
|
|
357
|
+
}
|
|
358
|
+
onFocusOut(event) {
|
|
359
|
+
const next = event.relatedTarget;
|
|
360
|
+
if (!next || !this.#host.nativeElement.contains(next)) {
|
|
361
|
+
this.markTouched();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** Field-specific `aria-valuetext`: only the empty marker; numeric otherwise. */
|
|
365
|
+
#valueText(type) {
|
|
366
|
+
return this.isSegmentEmpty(type) ? this.#defaults.emptySegmentText : null;
|
|
367
|
+
}
|
|
368
|
+
/** Base value for stepping an empty segment: midnight (hour 0, minute 0, second 0). */
|
|
369
|
+
#seed(type) {
|
|
370
|
+
if (type !== 'hour') {
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
const display = this.segmentMin('hour');
|
|
374
|
+
if (this.#cycle() === 24) {
|
|
375
|
+
return display;
|
|
376
|
+
}
|
|
377
|
+
const hour = this.#parts().hour;
|
|
378
|
+
const pm = hour !== null && hour >= 12;
|
|
379
|
+
const base = display % 12;
|
|
380
|
+
return pm ? base + 12 : base;
|
|
381
|
+
}
|
|
382
|
+
#placeholderFor(type) {
|
|
383
|
+
if (type === 'hour' || type === 'minute' || type === 'second' || type === 'dayPeriod') {
|
|
384
|
+
const override = this.placeholder()[type];
|
|
385
|
+
if (override) {
|
|
386
|
+
return override;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
switch (type) {
|
|
390
|
+
case 'hour':
|
|
391
|
+
return 'hh';
|
|
392
|
+
case 'minute':
|
|
393
|
+
return 'mm';
|
|
394
|
+
case 'second':
|
|
395
|
+
return 'ss';
|
|
396
|
+
default:
|
|
397
|
+
return '--';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
#commitParts(next) {
|
|
401
|
+
this.#parts.set(next);
|
|
402
|
+
const granularity = this.granularity();
|
|
403
|
+
const needMinute = granularity !== 'hour';
|
|
404
|
+
const needSecond = granularity === 'second';
|
|
405
|
+
const complete = next.hour !== null &&
|
|
406
|
+
(!needMinute || next.minute !== null) &&
|
|
407
|
+
(!needSecond || next.second !== null);
|
|
408
|
+
if (complete) {
|
|
409
|
+
const base = this.value() ?? timeSentinel(this.adapter);
|
|
410
|
+
const composed = this.adapter.setTime(base, next.hour, needMinute ? next.minute : 0, needSecond ? next.second : 0);
|
|
411
|
+
this.value.set(this.#clampToBounds(composed));
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
this.value.set(null);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
#clampToBounds(date) {
|
|
418
|
+
const min = this.minTime();
|
|
419
|
+
if (min !== null && secondsOfDay(this.adapter, date) < secondsOfDay(this.adapter, min)) {
|
|
420
|
+
return composeWithTime(this.adapter, date, min);
|
|
421
|
+
}
|
|
422
|
+
const max = this.maxTime();
|
|
423
|
+
if (max !== null && secondsOfDay(this.adapter, date) > secondsOfDay(this.adapter, max)) {
|
|
424
|
+
return composeWithTime(this.adapter, date, max);
|
|
425
|
+
}
|
|
426
|
+
return date;
|
|
427
|
+
}
|
|
428
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
429
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTimeField, isStandalone: true, selector: "[forTimeField]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minTime: { classPropertyName: "minTime", publicName: "minTime", isSignal: true, isRequired: false, transformFunction: null }, maxTime: { classPropertyName: "maxTime", publicName: "maxTime", isSignal: true, isRequired: false, transformFunction: null }, hourCycle: { classPropertyName: "hourCycle", publicName: "hourCycle", isSignal: true, isRequired: false, transformFunction: null }, granularity: { classPropertyName: "granularity", publicName: "granularity", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "group" }, listeners: { "focusout": "onFocusOut($event)" }, properties: { "attr.dir": "dir()", "attr.aria-label": "ariaLabel() || null", "attr.aria-disabled": "effectiveDisabled() ? \"true\" : null", "attr.aria-readonly": "readonly() ? \"true\" : null", "attr.aria-required": "required() ? \"true\" : null", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.data-disabled": "effectiveDisabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.data-empty": "value() === null ? \"\" : null" } }, providers: [
|
|
430
|
+
{ provide: FOR_TIME_FIELD_CONTEXT, useExisting: ForTimeField },
|
|
431
|
+
{ provide: FOR_TIME_VALUE_SOURCE, useExisting: ForTimeField },
|
|
432
|
+
], exportAs: ["forTimeField"], usesInheritance: true, ngImport: i0 });
|
|
433
|
+
}
|
|
434
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeField, decorators: [{
|
|
435
|
+
type: Directive,
|
|
436
|
+
args: [{
|
|
437
|
+
selector: '[forTimeField]',
|
|
438
|
+
exportAs: 'forTimeField',
|
|
439
|
+
host: {
|
|
440
|
+
role: 'group',
|
|
441
|
+
'[attr.dir]': 'dir()',
|
|
442
|
+
'[attr.aria-label]': 'ariaLabel() || null',
|
|
443
|
+
'[attr.aria-disabled]': 'effectiveDisabled() ? "true" : null',
|
|
444
|
+
'[attr.aria-readonly]': 'readonly() ? "true" : null',
|
|
445
|
+
'[attr.aria-required]': 'required() ? "true" : null',
|
|
446
|
+
'[attr.aria-invalid]': 'invalid() ? "true" : null',
|
|
447
|
+
'[attr.data-disabled]': 'effectiveDisabled() ? "" : null',
|
|
448
|
+
'[attr.data-readonly]': 'readonly() ? "" : null',
|
|
449
|
+
'[attr.data-empty]': 'value() === null ? "" : null',
|
|
450
|
+
'(focusout)': 'onFocusOut($event)',
|
|
451
|
+
},
|
|
452
|
+
providers: [
|
|
453
|
+
{ provide: FOR_TIME_FIELD_CONTEXT, useExisting: ForTimeField },
|
|
454
|
+
{ provide: FOR_TIME_VALUE_SOURCE, useExisting: ForTimeField },
|
|
455
|
+
],
|
|
456
|
+
}]
|
|
457
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }], hourCycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourCycle", required: false }] }], granularity: [{ type: i0.Input, args: [{ isSignal: true, alias: "granularity", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], _dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }] } });
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* One editable spinbutton segment of a `[forTimeField]` — the hour, minute,
|
|
461
|
+
* second, or AM/PM (`dayPeriod`) part. Apply on a focusable element (typically
|
|
462
|
+
* a `<span>`); the shared {@link ForDateTimeSegmentBase} adds
|
|
463
|
+
* `role="spinbutton"`, the `aria-valuemin` / `aria-valuemax` / `aria-valuenow` /
|
|
464
|
+
* `aria-valuetext` reflection, the roving tabindex, and the full keyboard map:
|
|
465
|
+
*
|
|
466
|
+
* - **digits** fill a numeric segment and auto-advance to the next when full;
|
|
467
|
+
* - **a / p** set the period on the `dayPeriod` segment;
|
|
468
|
+
* - **ArrowUp / ArrowDown** step the value (hour / minute / second wrap; dayPeriod toggles);
|
|
469
|
+
* - **ArrowLeft / ArrowRight** move between segments (mirrored under RTL, no wrap);
|
|
470
|
+
* - **Home / End** jump to the segment minimum / maximum (dayPeriod → AM / PM);
|
|
471
|
+
* - **Backspace / Delete** clear a numeric segment.
|
|
472
|
+
*
|
|
473
|
+
* All state lives on the root `ForTimeField`; the segment only reads it and
|
|
474
|
+
* forwards intents. The rendered text comes from the root's `segments()` list
|
|
475
|
+
* (`{{ seg.text }}`), so this element carries behavior and ARIA, not content.
|
|
476
|
+
*/
|
|
477
|
+
class ForTimeFieldSegment extends ForDateTimeSegmentBase {
|
|
478
|
+
ctx = injectTimeFieldContext('ForTimeFieldSegment');
|
|
479
|
+
#defaults = inject(FOR_TIME_FIELD_DEFAULTS);
|
|
480
|
+
/** Which time part this segment edits. */
|
|
481
|
+
segment = input.required(/* @ts-ignore */
|
|
482
|
+
...(ngDevMode ? [{ debugName: "segment" }] : /* istanbul ignore next */ []));
|
|
483
|
+
/**
|
|
484
|
+
* Accessible name for this segment. Falls back to the scope's localized
|
|
485
|
+
* default label for the part (via `provideForTimeFieldDefaults`), which in
|
|
486
|
+
* turn defaults to the part name — and `'AM/PM'` for the `dayPeriod` segment.
|
|
487
|
+
*/
|
|
488
|
+
ariaLabel = input(null, /* @ts-ignore */
|
|
489
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
490
|
+
resolvedAriaLabel = computed(() => {
|
|
491
|
+
const type = this.segment();
|
|
492
|
+
return (this.ariaLabel() ??
|
|
493
|
+
this.#defaults.segmentLabels[type] ??
|
|
494
|
+
DEFAULT_TIME_FIELD_SEGMENT_LABELS[type]);
|
|
495
|
+
}, /* @ts-ignore */
|
|
496
|
+
...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
|
|
497
|
+
constructor() {
|
|
498
|
+
super();
|
|
499
|
+
this.registerSegment();
|
|
500
|
+
}
|
|
501
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeFieldSegment, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
502
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForTimeFieldSegment, isStandalone: true, selector: "[forTimeFieldSegment]", inputs: { segment: { classPropertyName: "segment", publicName: "segment", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["forTimeFieldSegment"], usesInheritance: true, ngImport: i0 });
|
|
503
|
+
}
|
|
504
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeFieldSegment, decorators: [{
|
|
505
|
+
type: Directive,
|
|
506
|
+
args: [{
|
|
507
|
+
selector: '[forTimeFieldSegment]',
|
|
508
|
+
exportAs: 'forTimeFieldSegment',
|
|
509
|
+
}]
|
|
510
|
+
}], ctorParameters: () => [], propDecorators: { segment: [{ type: i0.Input, args: [{ isSignal: true, alias: "segment", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* A decorative separator (`:`, a space) between the editable segments of a
|
|
514
|
+
* `[forTimeField]`. Apply on the element rendering the literal text; it is
|
|
515
|
+
* marked `aria-hidden` and stays out of the tab order, so assistive tech reads
|
|
516
|
+
* only the spinbutton segments. The separator characters come from the root's
|
|
517
|
+
* locale-ordered `segments()` list (`{{ seg.text }}`).
|
|
518
|
+
*/
|
|
519
|
+
class ForTimeFieldLiteral extends ForDateTimeLiteralBase {
|
|
520
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeFieldLiteral, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
521
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: ForTimeFieldLiteral, isStandalone: true, selector: "[forTimeFieldLiteral]", exportAs: ["forTimeFieldLiteral"], usesInheritance: true, ngImport: i0 });
|
|
522
|
+
}
|
|
523
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForTimeFieldLiteral, decorators: [{
|
|
524
|
+
type: Directive,
|
|
525
|
+
args: [{
|
|
526
|
+
selector: '[forTimeFieldLiteral]',
|
|
527
|
+
exportAs: 'forTimeFieldLiteral',
|
|
528
|
+
}]
|
|
529
|
+
}] });
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Exact public names of every `ForTimeField` input, its models included. Spread it into the
|
|
533
|
+
* `inputs` array of a `hostDirectives` entry so a wrapper component re-exposes the
|
|
534
|
+
* primitive's full surface — the Signal Forms members `[formField]` binds among them —
|
|
535
|
+
* without hand-maintaining the list. Always spread into an inline object literal as shown
|
|
536
|
+
* below: the literal is what keeps the entry statically analyzable for consumers compiling
|
|
537
|
+
* against the published package. An anti-drift spec fails when this list no longer matches
|
|
538
|
+
* the directive's actual API. See `docs/wrapping-form-primitives.md` for both supported
|
|
539
|
+
* wrapping patterns.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```ts
|
|
543
|
+
* @Component({
|
|
544
|
+
* selector: 'div[myTimeField]',
|
|
545
|
+
* template: '',
|
|
546
|
+
* hostDirectives: [
|
|
547
|
+
* {
|
|
548
|
+
* directive: ForTimeField,
|
|
549
|
+
* inputs: [...FOR_TIME_FIELD_HOST_DIRECTIVE_INPUTS],
|
|
550
|
+
* outputs: [...FOR_TIME_FIELD_HOST_DIRECTIVE_OUTPUTS],
|
|
551
|
+
* },
|
|
552
|
+
* ],
|
|
553
|
+
* })
|
|
554
|
+
* export class MyTimeField {}
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
const FOR_TIME_FIELD_HOST_DIRECTIVE_INPUTS = [
|
|
558
|
+
'value',
|
|
559
|
+
'ariaLabel',
|
|
560
|
+
'dir',
|
|
561
|
+
'dirty',
|
|
562
|
+
'disabled',
|
|
563
|
+
'errors',
|
|
564
|
+
'granularity',
|
|
565
|
+
'hourCycle',
|
|
566
|
+
'invalid',
|
|
567
|
+
'locale',
|
|
568
|
+
'maxTime',
|
|
569
|
+
'minTime',
|
|
570
|
+
'name',
|
|
571
|
+
'pending',
|
|
572
|
+
'placeholder',
|
|
573
|
+
'readonly',
|
|
574
|
+
'required',
|
|
575
|
+
'touched',
|
|
576
|
+
];
|
|
577
|
+
/**
|
|
578
|
+
* Exact public names of every `ForTimeField` output, the Signal Forms `touch` output
|
|
579
|
+
* included. Spread it into the `outputs` array of the same `hostDirectives` entry as
|
|
580
|
+
* {@link FOR_TIME_FIELD_HOST_DIRECTIVE_INPUTS}.
|
|
581
|
+
*/
|
|
582
|
+
const FOR_TIME_FIELD_HOST_DIRECTIVE_OUTPUTS = [
|
|
583
|
+
'valueChange',
|
|
584
|
+
'touchedChange',
|
|
585
|
+
'touch',
|
|
586
|
+
];
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Generated bundle index. Do not edit.
|
|
590
|
+
*/
|
|
591
|
+
|
|
592
|
+
export { DEFAULT_TIME_FIELD_SEGMENT_LABELS, FOR_TIME_FIELD_CONTEXT, FOR_TIME_FIELD_DEFAULTS, FOR_TIME_FIELD_HOST_DIRECTIVE_INPUTS, FOR_TIME_FIELD_HOST_DIRECTIVE_OUTPUTS, ForTimeField, ForTimeFieldLiteral, ForTimeFieldSegment, provideForTimeFieldDefaults };
|
|
593
|
+
//# sourceMappingURL=forty-cdk-time-field.mjs.map
|