@cdevhub/ngx-tw 0.5.0 → 0.6.1
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 +78 -15
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +11 -2
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +28 -4
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs → cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs} +3 -3
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +23 -7
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs → cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs} +107 -19
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +21 -13
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
- package/index.json +1 -1
- package/package.json +63 -2
- package/theme/_base.css +13 -0
- package/theme/_dark.css +111 -36
- package/theme/_high-contrast-dark.css +367 -0
- package/theme/_high-contrast.css +13 -2
- package/theme/_light.css +332 -0
- package/theme/_semantic.css +60 -26
- package/theme/_typography.css +17 -0
- package/theme/index.css +86 -7
- package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
- package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
- package/types/cdevhub-ngx-tw-button.d.ts +1 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
- package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
- package/types/cdevhub-ngx-tw-card.d.ts +11 -3
- package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
- package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
- package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
- package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
- package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
- package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
- package/types/cdevhub-ngx-tw-core.d.ts +152 -21
- package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
- package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
- package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +12 -3
- package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
- package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
- package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
- package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
- package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
- package/types/cdevhub-ngx-tw-input.d.ts +5 -8
- package/types/cdevhub-ngx-tw-item.d.ts +2 -0
- package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
- package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
- package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
- package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
- package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
- package/types/cdevhub-ngx-tw-select.d.ts +104 -33
- package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +19 -3
- package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
- package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
- package/types/cdevhub-ngx-tw-split.d.ts +32 -2
- package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
- package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
- package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
- package/types/cdevhub-ngx-tw-table.d.ts +53 -10
- package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
- package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
- package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
- package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
- package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
- package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
- package/types/cdevhub-ngx-tw-toast.d.ts +20 -6
- package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
- package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
- package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
- package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs.map +0 -1
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs.map +0 -1
|
@@ -32,16 +32,13 @@ class CalendarHeaderComponent {
|
|
|
32
32
|
/** Accessible label for the next button. */
|
|
33
33
|
nextAriaLabel = input.required(/* @ts-ignore */
|
|
34
34
|
...(ngDevMode ? [{ debugName: "nextAriaLabel" }] : /* istanbul ignore next */ []));
|
|
35
|
-
/** Disables the previous button. */
|
|
35
|
+
/** Disables the previous button — set by the orchestrator when `minDate` blocks backward navigation. Defaults to `false`. */
|
|
36
36
|
prevDisabled = input(false, /* @ts-ignore */
|
|
37
37
|
...(ngDevMode ? [{ debugName: "prevDisabled" }] : /* istanbul ignore next */ []));
|
|
38
|
-
/** Disables the next button. */
|
|
38
|
+
/** Disables the next button — set by the orchestrator when `maxDate` blocks forward navigation. Defaults to `false`. */
|
|
39
39
|
nextDisabled = input(false, /* @ts-ignore */
|
|
40
40
|
...(ngDevMode ? [{ debugName: "nextDisabled" }] : /* istanbul ignore next */ []));
|
|
41
|
-
/** When false, the period button is disabled (e.g. when already at the top view). */
|
|
42
|
-
// TRUE-default: the period button is the calendar header's primary drill-up
|
|
43
|
-
// affordance; disabling it is reserved for the top view where there's nowhere
|
|
44
|
-
// to drill up to.
|
|
41
|
+
/** When false, the period button is disabled (e.g. when already at the top view). Defaults to `true` — the period button is the header's primary drill-up affordance; the special case is the top view, where there is nowhere to drill up to. */
|
|
45
42
|
canSwitchView = input(true, /* @ts-ignore */
|
|
46
43
|
...(ngDevMode ? [{ debugName: "canSwitchView" }] : /* istanbul ignore next */ []));
|
|
47
44
|
/** Fires on previous button click. */
|
|
@@ -396,11 +393,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
396
393
|
* Provides a custom `CalendarIntl` instance. Place at any injector level —
|
|
397
394
|
* the calendar resolves the closest one and merges any per-instance `intl`
|
|
398
395
|
* input on top of it (§19.4 per-field merge semantics).
|
|
396
|
+
*
|
|
397
|
+
* Keys explicitly set to `undefined` are dropped before merging. Root
|
|
398
|
+
* `tsconfig.json` does not set `exactOptionalPropertyTypes`, so
|
|
399
|
+
* `provideCalendarIntl({ monthViewLabel: bundle['calendar.monthView'] })`
|
|
400
|
+
* type-checks even when the lookup misses — and a plain `Object.assign` would
|
|
401
|
+
* then copy that `undefined` over a field `CalendarIntl` types as `string`.
|
|
402
|
+
* Because this is a bootstrap-level provider, one missing key in an i18n
|
|
403
|
+
* bundle broke *every* calendar in the app, and the failure surfaced far from
|
|
404
|
+
* the call site: `viewSwitched()` calls `.replace()` on the label directly, so
|
|
405
|
+
* the first drill-up threw `Cannot read properties of undefined (reading
|
|
406
|
+
* 'replace')`. Filtering here makes a missing key fall back to the English
|
|
407
|
+
* default instead.
|
|
399
408
|
*/
|
|
400
409
|
function provideCalendarIntl(custom) {
|
|
401
410
|
return {
|
|
402
411
|
provide: CalendarIntl,
|
|
403
|
-
useFactory: () =>
|
|
412
|
+
useFactory: () => {
|
|
413
|
+
const overrides = Object.fromEntries(Object.entries(custom ?? {}).filter(([, value]) => value !== undefined));
|
|
414
|
+
return Object.assign(new CalendarIntl(), overrides);
|
|
415
|
+
},
|
|
404
416
|
};
|
|
405
417
|
}
|
|
406
418
|
|
|
@@ -819,16 +831,37 @@ function calendarRequiredValidator(mode) {
|
|
|
819
831
|
* When set, TZ-aware adapters resolve `today()` and date-range math against
|
|
820
832
|
* the supplied IANA timezone. Floating (naive) adapters ignore the token.
|
|
821
833
|
*/
|
|
822
|
-
const
|
|
834
|
+
const TW_TZ_OVERRIDE = new InjectionToken('tw-calendar/TZ_OVERRIDE');
|
|
835
|
+
/**
|
|
836
|
+
* @deprecated Renamed to {@link TW_TZ_OVERRIDE} for consistency with every other
|
|
837
|
+
* ngx-tw injection token. This is the *same token instance*, not a copy —
|
|
838
|
+
* providing under either name and injecting under the other resolves — so the
|
|
839
|
+
* rename is safe to adopt incrementally. Removed in the next major.
|
|
840
|
+
*/
|
|
841
|
+
const TZ_OVERRIDE = TW_TZ_OVERRIDE;
|
|
823
842
|
/**
|
|
824
843
|
* Injection token for the default value transformer (§7.4, §7.6). Phase 14 wires
|
|
825
844
|
* the component-level `valueTransformer` input to override this DI default.
|
|
826
845
|
* Shipped as a token shell now so later phases can bind against it without a
|
|
827
846
|
* breaking change.
|
|
828
847
|
*/
|
|
829
|
-
const
|
|
848
|
+
const TW_DATE_SERIALIZATION = new InjectionToken('tw-calendar/DATE_SERIALIZATION');
|
|
849
|
+
/**
|
|
850
|
+
* @deprecated Renamed to {@link TW_DATE_SERIALIZATION} for consistency with
|
|
851
|
+
* every other ngx-tw injection token. This is the *same token instance*, not a
|
|
852
|
+
* copy — providing under either name and injecting under the other resolves —
|
|
853
|
+
* so the rename is safe to adopt incrementally. Removed in the next major.
|
|
854
|
+
*/
|
|
855
|
+
const DATE_SERIALIZATION = TW_DATE_SERIALIZATION;
|
|
830
856
|
/** DI token carrying the default `DateFormats`. The calendar's `dateFormats` input overrides. */
|
|
831
|
-
const
|
|
857
|
+
const TW_DATE_FORMATS = new InjectionToken('tw-calendar/DateFormats');
|
|
858
|
+
/**
|
|
859
|
+
* @deprecated Renamed to {@link TW_DATE_FORMATS} for consistency with every
|
|
860
|
+
* other ngx-tw injection token. This is the *same token instance*, not a copy —
|
|
861
|
+
* providing under either name and injecting under the other resolves — so the
|
|
862
|
+
* rename is safe to adopt incrementally. Removed in the next major.
|
|
863
|
+
*/
|
|
864
|
+
const DATE_FORMATS = TW_DATE_FORMATS;
|
|
832
865
|
/**
|
|
833
866
|
* Abstract date adapter. Ship a subclass to swap the underlying date library
|
|
834
867
|
* (Luxon, date-fns, Temporal). The calendar consumes only the methods defined
|
|
@@ -911,18 +944,50 @@ class DateAdapter {
|
|
|
911
944
|
* Injection token for the calendar's `DateAdapter`. Prefer `provideNativeDateAdapter()`
|
|
912
945
|
* or `provideTwCalendar({ adapter })` over binding this token directly.
|
|
913
946
|
*/
|
|
914
|
-
const
|
|
947
|
+
const TW_DATE_ADAPTER = new InjectionToken('tw-calendar/DateAdapter');
|
|
948
|
+
/**
|
|
949
|
+
* @deprecated Renamed to {@link TW_DATE_ADAPTER} for consistency with every
|
|
950
|
+
* other ngx-tw injection token. This is the *same token instance*, not a copy —
|
|
951
|
+
* providing under either name and injecting under the other resolves, so an app
|
|
952
|
+
* that provides `DATE_ADAPTER` keeps working against a library that injects
|
|
953
|
+
* `TW_DATE_ADAPTER`. Removed in the next major.
|
|
954
|
+
*/
|
|
955
|
+
const DATE_ADAPTER = TW_DATE_ADAPTER;
|
|
915
956
|
|
|
916
957
|
const cellVariants = tv({
|
|
917
958
|
slots: {
|
|
918
959
|
wrapper: 'relative flex items-center justify-center',
|
|
919
|
-
|
|
960
|
+
// `aria-disabled:` rather than `disabled:` — the button never carries the
|
|
961
|
+
// native `disabled` attribute (see the host template), so the `disabled:`
|
|
962
|
+
// variant would never match.
|
|
963
|
+
button: 'relative flex items-center justify-center cursor-pointer select-none transition-colors duration-normal motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 aria-disabled:cursor-not-allowed',
|
|
920
964
|
},
|
|
921
965
|
variants: {
|
|
966
|
+
// Every view's cell is `h-9` — the 36px `md` control height from
|
|
967
|
+
// docs/vertical-rhythm.md. Month and year cells were `h-10`, which made a
|
|
968
|
+
// month-picker row 4px taller than a day row for no reason and put the
|
|
969
|
+
// value off the height scale. Only the width differs per view (a day is
|
|
970
|
+
// one or two digits in a circle; a month/year is a 3–4 char label in a
|
|
971
|
+
// rounded rect). The panel's height is pinned separately — see the
|
|
972
|
+
// view-region wrapper in `calendar.ts`.
|
|
973
|
+
//
|
|
974
|
+
// Widths are chosen so all three grids compute to the SAME 252px intrinsic
|
|
975
|
+
// width, which is what stops the panel shifting horizontally on a view
|
|
976
|
+
// switch. The day grid is `grid-cols-7 gap-0`: 7 x 36 = 252. The month and
|
|
977
|
+
// year grids are `grid-cols-4 gap-1`: 4 x 60 + 3 x 4 = 252. Month cells were
|
|
978
|
+
// `w-16` (4 x 64 + 12 = 268) and year cells `w-14` (4 x 56 + 12 = 236), which
|
|
979
|
+
// is where the 270 / 286 / 254 panel spread came from.
|
|
980
|
+
//
|
|
981
|
+
// The day cell is deliberately untouched: its `w-9` button has to coincide
|
|
982
|
+
// exactly with its grid column so the range wrapper's `rounded-l-full` /
|
|
983
|
+
// `rounded-r-full` cap lands on the selected endpoint pill instead of ~1px
|
|
984
|
+
// past it. Equalising via the month and year cells keeps that coincidence
|
|
985
|
+
// intact by construction, where a `min-w` on the shared view region would
|
|
986
|
+
// have broken it — see the note in `calendar.ts`.
|
|
922
987
|
view: {
|
|
923
988
|
day: { button: 'h-9 w-9 text-sm rounded-full' },
|
|
924
|
-
month: { button: 'h-
|
|
925
|
-
year: { button: 'h-
|
|
989
|
+
month: { button: 'h-9 w-15 text-sm rounded-md' },
|
|
990
|
+
year: { button: 'h-9 w-15 text-sm rounded-md' },
|
|
926
991
|
},
|
|
927
992
|
// Slot tokens own light/dark contrast — no `dark:`, no shade picks.
|
|
928
993
|
// The range wash uses `primary-soft-hover` (one step deeper than `-soft`)
|
|
@@ -987,16 +1052,16 @@ class CalendarCellComponent {
|
|
|
987
1052
|
/** The cell data object to render. */
|
|
988
1053
|
cell = input.required(/* @ts-ignore */
|
|
989
1054
|
...(ngDevMode ? [{ debugName: "cell" }] : /* istanbul ignore next */ []));
|
|
990
|
-
/** The active calendar view — drives cell
|
|
1055
|
+
/** The active calendar view — drives cell width and radius. Defaults to `'day'`. */
|
|
991
1056
|
view = input('day', /* @ts-ignore */
|
|
992
1057
|
...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
993
|
-
/** `true` when the cell's date is outside the currently displayed month. */
|
|
1058
|
+
/** `true` when the cell's date is outside the currently displayed month, which mutes its text. Defaults to `false`. */
|
|
994
1059
|
outside = input(false, /* @ts-ignore */
|
|
995
1060
|
...(ngDevMode ? [{ debugName: "outside" }] : /* istanbul ignore next */ []));
|
|
996
|
-
/** Tab index for roving focus (`0` for the active cell, `-1` otherwise). */
|
|
1061
|
+
/** Tab index for roving focus (`0` for the active cell, `-1` otherwise). Defaults to `-1`. */
|
|
997
1062
|
tabindex = input(-1, /* @ts-ignore */
|
|
998
1063
|
...(ngDevMode ? [{ debugName: "tabindex" }] : /* istanbul ignore next */ []));
|
|
999
|
-
/** Optional template rendered inside the button — receives `{ $implicit: CalendarCell<D> }`. */
|
|
1064
|
+
/** Optional template rendered inside the button — receives `{ $implicit: CalendarCell<D> }`. Defaults to `null` (the cell renders its own display value). */
|
|
1000
1065
|
cellTemplate = input(null, /* @ts-ignore */
|
|
1001
1066
|
...(ngDevMode ? [{ debugName: "cellTemplate" }] : /* istanbul ignore next */ []));
|
|
1002
1067
|
/** Emitted when the user activates the cell (click, Enter, or Space). */
|
|
@@ -1088,6 +1153,12 @@ class CalendarCellComponent {
|
|
|
1088
1153
|
}
|
|
1089
1154
|
}
|
|
1090
1155
|
onMouseEnter() {
|
|
1156
|
+
// Browsers do not dispatch mouse events on a natively disabled button, so
|
|
1157
|
+
// before the switch to `aria-disabled` a disabled cell never previewed.
|
|
1158
|
+
// Guard explicitly to keep range preview from extending over dates the user
|
|
1159
|
+
// cannot pick.
|
|
1160
|
+
if (!this.cell().enabled)
|
|
1161
|
+
return;
|
|
1091
1162
|
this.previewed.emit(this.cell());
|
|
1092
1163
|
}
|
|
1093
1164
|
onFocus() {
|
|
@@ -1098,18 +1169,25 @@ class CalendarCellComponent {
|
|
|
1098
1169
|
this.buttonRef()?.nativeElement.focus();
|
|
1099
1170
|
}
|
|
1100
1171
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: CalendarCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1101
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: CalendarCellComponent, isStandalone: true, selector: "tw-calendar-cell", inputs: { cell: { classPropertyName: "cell", publicName: "cell", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, outside: { classPropertyName: "outside", publicName: "outside", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", focused: "focused", previewed: "previewed", keyNav: "keyNav" }, host: { attributes: { "role": "gridcell" }, properties: { "attr.data-state-today": "cell().isToday ? '' : null", "attr.data-state-selected": "cell().isSelected && !cell().isRangeStart && !cell().isRangeEnd && !cell().isRangeMiddle ? '' : null", "attr.data-state-range-start": "cell().isRangeStart ? '' : null", "attr.data-state-range-end": "cell().isRangeEnd ? '' : null", "attr.data-state-in-range": "cell().isRangeMiddle ? '' : null", "attr.data-state-range-preview-start": "cell().isPreviewStart ? '' : null", "attr.data-state-range-preview-end": "cell().isPreviewEnd ? '' : null", "attr.data-state-in-range-preview": "cell().isPreviewMiddle ? '' : null", "attr.data-state-invalid-preview": "cell().isInvalidPreview ? '' : null", "attr.data-state-invalid-flash": "cell().isInvalidFlash ? '' : null", "attr.data-state-disabled": "!cell().enabled ? '' : null", "attr.data-state-out-of-month": "outside() ? '' : null", "attr.data-state-weekend": "cell().isWeekend ? '' : null", "attr.data-state-focused": "tabindex() === 0 ? '' : null" } }, viewQueries: [{ propertyName: "buttonRef", first: true, predicate: ["cellButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1172
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: CalendarCellComponent, isStandalone: true, selector: "tw-calendar-cell", inputs: { cell: { classPropertyName: "cell", publicName: "cell", isSignal: true, isRequired: true, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, outside: { classPropertyName: "outside", publicName: "outside", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", focused: "focused", previewed: "previewed", keyNav: "keyNav" }, host: { attributes: { "role": "gridcell" }, properties: { "attr.aria-selected": "cell().isSelected || null", "attr.data-state-today": "cell().isToday ? '' : null", "attr.data-state-selected": "cell().isSelected && !cell().isRangeStart && !cell().isRangeEnd && !cell().isRangeMiddle ? '' : null", "attr.data-state-range-start": "cell().isRangeStart ? '' : null", "attr.data-state-range-end": "cell().isRangeEnd ? '' : null", "attr.data-state-in-range": "cell().isRangeMiddle ? '' : null", "attr.data-state-range-preview-start": "cell().isPreviewStart ? '' : null", "attr.data-state-range-preview-end": "cell().isPreviewEnd ? '' : null", "attr.data-state-in-range-preview": "cell().isPreviewMiddle ? '' : null", "attr.data-state-invalid-preview": "cell().isInvalidPreview ? '' : null", "attr.data-state-invalid-flash": "cell().isInvalidFlash ? '' : null", "attr.data-state-disabled": "!cell().enabled ? '' : null", "attr.data-state-out-of-month": "outside() ? '' : null", "attr.data-state-weekend": "cell().isWeekend ? '' : null", "attr.data-state-focused": "tabindex() === 0 ? '' : null" } }, viewQueries: [{ propertyName: "buttonRef", first: true, predicate: ["cellButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1102
1173
|
<div [class]="wrapperClasses()">
|
|
1174
|
+
<!--
|
|
1175
|
+
No native disabled attribute. A disabled button cannot take DOM focus,
|
|
1176
|
+
so focusButton was a silent no-op on any out-of-range cell and the
|
|
1177
|
+
roving tabindex drifted out of sync with the real activeElement -
|
|
1178
|
+
pressing Tab into a grid whose cursor sat on a bounded date focused
|
|
1179
|
+
nothing at all. APG uses aria-disabled for grid cells for exactly this
|
|
1180
|
+
reason: the cell stays focusable and announceable, while activation is
|
|
1181
|
+
refused in onClick and onKeydown.
|
|
1182
|
+
-->
|
|
1103
1183
|
<button
|
|
1104
1184
|
#cellButton
|
|
1105
1185
|
type="button"
|
|
1106
1186
|
[class]="buttonClasses()"
|
|
1107
1187
|
[attr.aria-label]="cell().ariaLabel"
|
|
1108
|
-
[attr.aria-selected]="cell().isSelected || null"
|
|
1109
1188
|
[attr.aria-disabled]="!cell().enabled || null"
|
|
1110
1189
|
[attr.aria-current]="cell().isToday ? 'date' : null"
|
|
1111
1190
|
[attr.tabindex]="tabindex()"
|
|
1112
|
-
[disabled]="!cell().enabled"
|
|
1113
1191
|
(click)="onClick()"
|
|
1114
1192
|
(keydown)="onKeydown($event)"
|
|
1115
1193
|
(mouseenter)="onMouseEnter()"
|
|
@@ -1135,6 +1213,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
1135
1213
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1136
1214
|
host: {
|
|
1137
1215
|
role: 'gridcell',
|
|
1216
|
+
// `aria-selected` belongs HERE, not on the inner <button>. A button's
|
|
1217
|
+
// implicit role does not support `aria-selected`, so the previous binding
|
|
1218
|
+
// exposed nothing: the selected day's state was invisible to assistive tech
|
|
1219
|
+
// (SC 4.1.2). `gridcell` is the role that carries selection state, and it is
|
|
1220
|
+
// the element the grid/row structure actually addresses.
|
|
1221
|
+
'[attr.aria-selected]': "cell().isSelected || null",
|
|
1138
1222
|
// Phase 4 — `data-state-*` styling contract (§34.5). Each attribute is `''`
|
|
1139
1223
|
// when its boolean state is true and absent (`null`) otherwise so consumers
|
|
1140
1224
|
// can target via `tw-calendar-cell[data-state-today]` selectors.
|
|
@@ -1155,16 +1239,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
1155
1239
|
},
|
|
1156
1240
|
template: `
|
|
1157
1241
|
<div [class]="wrapperClasses()">
|
|
1242
|
+
<!--
|
|
1243
|
+
No native disabled attribute. A disabled button cannot take DOM focus,
|
|
1244
|
+
so focusButton was a silent no-op on any out-of-range cell and the
|
|
1245
|
+
roving tabindex drifted out of sync with the real activeElement -
|
|
1246
|
+
pressing Tab into a grid whose cursor sat on a bounded date focused
|
|
1247
|
+
nothing at all. APG uses aria-disabled for grid cells for exactly this
|
|
1248
|
+
reason: the cell stays focusable and announceable, while activation is
|
|
1249
|
+
refused in onClick and onKeydown.
|
|
1250
|
+
-->
|
|
1158
1251
|
<button
|
|
1159
1252
|
#cellButton
|
|
1160
1253
|
type="button"
|
|
1161
1254
|
[class]="buttonClasses()"
|
|
1162
1255
|
[attr.aria-label]="cell().ariaLabel"
|
|
1163
|
-
[attr.aria-selected]="cell().isSelected || null"
|
|
1164
1256
|
[attr.aria-disabled]="!cell().enabled || null"
|
|
1165
1257
|
[attr.aria-current]="cell().isToday ? 'date' : null"
|
|
1166
1258
|
[attr.tabindex]="tabindex()"
|
|
1167
|
-
[disabled]="!cell().enabled"
|
|
1168
1259
|
(click)="onClick()"
|
|
1169
1260
|
(keydown)="onKeydown($event)"
|
|
1170
1261
|
(mouseenter)="onMouseEnter()"
|
|
@@ -1191,47 +1282,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
1191
1282
|
* `getActiveCompareValue`.
|
|
1192
1283
|
*/
|
|
1193
1284
|
class CalendarViewBase {
|
|
1194
|
-
dateAdapter = inject(
|
|
1285
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
1195
1286
|
/** The date that anchors the grid being rendered. */
|
|
1196
1287
|
activeDate = input.required(/* @ts-ignore */
|
|
1197
1288
|
...(ngDevMode ? [{ debugName: "activeDate" }] : /* istanbul ignore next */ []));
|
|
1198
|
-
/** Current selection — scalar, array (multi), or range. */
|
|
1289
|
+
/** Current selection — scalar, array (multi), or range. Defaults to `null` (nothing selected). */
|
|
1199
1290
|
selected = input(null, /* @ts-ignore */
|
|
1200
1291
|
...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
1201
|
-
/** Minimum selectable date. */
|
|
1292
|
+
/** Minimum selectable date. Defaults to `null` (no lower bound). */
|
|
1202
1293
|
minDate = input(null, /* @ts-ignore */
|
|
1203
1294
|
...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
|
|
1204
|
-
/** Maximum selectable date. */
|
|
1295
|
+
/** Maximum selectable date. Defaults to `null` (no upper bound). */
|
|
1205
1296
|
maxDate = input(null, /* @ts-ignore */
|
|
1206
1297
|
...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
|
|
1207
|
-
/** Per-date predicate — return `false` to disable. */
|
|
1298
|
+
/** Per-date predicate — return `false` to disable. Defaults to `null` (every date passes). */
|
|
1208
1299
|
dateFilter = input(null, /* @ts-ignore */
|
|
1209
1300
|
...(ngDevMode ? [{ debugName: "dateFilter" }] : /* istanbul ignore next */ []));
|
|
1210
|
-
/** Explicitly disabled dates — array (compared via `adapter.sameDate`) or predicate (returns `true` for disabled). */
|
|
1301
|
+
/** Explicitly disabled dates — array (compared via `adapter.sameDate`) or predicate (returns `true` for disabled). Defaults to `null` (none). */
|
|
1211
1302
|
disabledDates = input(null, /* @ts-ignore */
|
|
1212
1303
|
...(ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []));
|
|
1213
|
-
/** Days of the week to disable (0=Sun … 6=Sat).
|
|
1304
|
+
/** Days of the week to disable (0=Sun … 6=Sat). Defaults to `[]` — no day-of-week disabling. */
|
|
1214
1305
|
disabledDaysOfWeek = input([], /* @ts-ignore */
|
|
1215
1306
|
...(ngDevMode ? [{ debugName: "disabledDaysOfWeek" }] : /* istanbul ignore next */ []));
|
|
1216
|
-
/** Per-cell class override. */
|
|
1307
|
+
/** Per-cell class override — returns extra classes appended to the cell button. Defaults to `null` (no extra classes). */
|
|
1217
1308
|
dateClass = input(null, /* @ts-ignore */
|
|
1218
1309
|
...(ngDevMode ? [{ debugName: "dateClass" }] : /* istanbul ignore next */ []));
|
|
1219
|
-
/** Hover-preview start (set while user is mid-range pick). */
|
|
1310
|
+
/** Hover-preview start (set while user is mid-range pick). Defaults to `null` (no preview). */
|
|
1220
1311
|
previewStart = input(null, /* @ts-ignore */
|
|
1221
1312
|
...(ngDevMode ? [{ debugName: "previewStart" }] : /* istanbul ignore next */ []));
|
|
1222
|
-
/** Hover-preview end. */
|
|
1313
|
+
/** Hover-preview end. Defaults to `null` (no preview). */
|
|
1223
1314
|
previewEnd = input(null, /* @ts-ignore */
|
|
1224
1315
|
...(ngDevMode ? [{ debugName: "previewEnd" }] : /* istanbul ignore next */ []));
|
|
1225
|
-
/** Phase 6 — date that briefly flashes as invalid (rejected commit). Cleared by the orchestrator. */
|
|
1316
|
+
/** Phase 6 — date that briefly flashes as invalid (rejected commit). Cleared by the orchestrator. Defaults to `null` (no flash). */
|
|
1226
1317
|
invalidFlashDate = input(null, /* @ts-ignore */
|
|
1227
1318
|
...(ngDevMode ? [{ debugName: "invalidFlashDate" }] : /* istanbul ignore next */ []));
|
|
1228
|
-
/** `true` when the parent calendar allows more than one cell to be selected at once. Drives `aria-multiselectable` on the grid host. */
|
|
1319
|
+
/** `true` when the parent calendar allows more than one cell to be selected at once. Drives `aria-multiselectable` on the grid host. Defaults to `false`. */
|
|
1229
1320
|
multiSelectable = input(false, /* @ts-ignore */
|
|
1230
1321
|
...(ngDevMode ? [{ debugName: "multiSelectable" }] : /* istanbul ignore next */ []));
|
|
1231
|
-
/** `true` when the parent calendar is in read-only mode. Drives `aria-readonly` on the grid host. */
|
|
1322
|
+
/** `true` when the parent calendar is in read-only mode. Drives `aria-readonly` on the grid host. Defaults to `false`. */
|
|
1232
1323
|
readonlyGrid = input(false, /* @ts-ignore */
|
|
1233
1324
|
...(ngDevMode ? [{ debugName: "readonlyGrid" }] : /* istanbul ignore next */ []));
|
|
1234
|
-
/**
|
|
1325
|
+
/**
|
|
1326
|
+
* `true` when the parent calendar is disabled (the `disabled` input, or a
|
|
1327
|
+
* bound form control's `setDisabledState`). Every cell then reports
|
|
1328
|
+
* `aria-disabled` and refuses activation. Defaults to `false`.
|
|
1329
|
+
*
|
|
1330
|
+
* Distinct from `readonlyGrid`: read-only keeps cells *selectable-looking*
|
|
1331
|
+
* and only blocks the commit in the orchestrator, whereas disabled removes
|
|
1332
|
+
* the affordance itself. Both leave the grid focusable and arrow-navigable —
|
|
1333
|
+
* per WAI-ARIA APG, a focusable disabled element stays "operable to the
|
|
1334
|
+
* extent of allowing the user to read its state", and `rovingCellValue`
|
|
1335
|
+
* guarantees exactly one tabbable cell so the grid never drops out of the
|
|
1336
|
+
* tab order.
|
|
1337
|
+
*/
|
|
1338
|
+
disabledGrid = input(false, /* @ts-ignore */
|
|
1339
|
+
...(ngDevMode ? [{ debugName: "disabledGrid" }] : /* istanbul ignore next */ []));
|
|
1340
|
+
/** Optional cell-content override, rendered inside each cell button with `{ $implicit: CalendarCell<D> }`. Defaults to `null` (the cell renders its own display value). */
|
|
1235
1341
|
cellTemplate = input(null, /* @ts-ignore */
|
|
1236
1342
|
...(ngDevMode ? [{ debugName: "cellTemplate" }] : /* istanbul ignore next */ []));
|
|
1237
1343
|
/** Fires when the user activates an enabled cell (click, Enter, or Space). Payload is the activated cell's date. */
|
|
@@ -1332,12 +1438,52 @@ class CalendarViewBase {
|
|
|
1332
1438
|
onGridMouseLeave() {
|
|
1333
1439
|
this.previewChange.emit(null);
|
|
1334
1440
|
}
|
|
1441
|
+
/**
|
|
1442
|
+
* `compareValue` of the cell that owns the roving tabindex, resolved against
|
|
1443
|
+
* the cells actually rendered right now.
|
|
1444
|
+
*
|
|
1445
|
+
* `focusedCellValue` is written only by `focusCell()` and nothing ever resets
|
|
1446
|
+
* it, so it goes stale the moment the displayed period changes by any route
|
|
1447
|
+
* that does not itself call `focusCell()` — the header's prev/next buttons,
|
|
1448
|
+
* a programmatic `activeDate` assignment, a view switch. A stale value
|
|
1449
|
+
* matches no rendered cell, `isActiveCell` then answered `false` for every
|
|
1450
|
+
* one of them, and the grid left the tab order entirely: zero cells with
|
|
1451
|
+
* `tabindex="0"`, nothing to Tab into, keyboard users locked out (SC 2.1.1).
|
|
1452
|
+
*
|
|
1453
|
+
* Resolving here rather than resetting the signal keeps this a pure read —
|
|
1454
|
+
* no effect, no write, no cycle — and the three fallbacks guarantee the
|
|
1455
|
+
* invariant the defect broke: a non-empty grid always has exactly one
|
|
1456
|
+
* tabbable cell.
|
|
1457
|
+
*/
|
|
1458
|
+
rovingCellValue = computed(() => {
|
|
1459
|
+
const grid = this.cells();
|
|
1460
|
+
const focused = this.focusedCellValue();
|
|
1461
|
+
if (focused !== null && this.gridHasValue(grid, focused))
|
|
1462
|
+
return focused;
|
|
1463
|
+
const active = this.getActiveCompareValue();
|
|
1464
|
+
if (this.gridHasValue(grid, active))
|
|
1465
|
+
return active;
|
|
1466
|
+
// Neither anchor is on screen. Rather than strand the grid, hand the cursor
|
|
1467
|
+
// to the first selectable cell — or, if every cell is disabled, the first
|
|
1468
|
+
// cell, which is still focusable now that cells use `aria-disabled`.
|
|
1469
|
+
for (const row of grid) {
|
|
1470
|
+
const enabled = row.find((c) => c.enabled);
|
|
1471
|
+
if (enabled)
|
|
1472
|
+
return enabled.compareValue;
|
|
1473
|
+
}
|
|
1474
|
+
for (const row of grid) {
|
|
1475
|
+
if (row.length > 0)
|
|
1476
|
+
return row[0].compareValue;
|
|
1477
|
+
}
|
|
1478
|
+
return null;
|
|
1479
|
+
}, /* @ts-ignore */
|
|
1480
|
+
...(ngDevMode ? [{ debugName: "rovingCellValue" }] : /* istanbul ignore next */ []));
|
|
1481
|
+
gridHasValue(grid, value) {
|
|
1482
|
+
return grid.some((row) => row.some((c) => c.compareValue === value));
|
|
1483
|
+
}
|
|
1335
1484
|
/** Returns `true` when the cell owns the roving cursor. */
|
|
1336
1485
|
isActiveCell(cell) {
|
|
1337
|
-
|
|
1338
|
-
if (focused !== null)
|
|
1339
|
-
return cell.compareValue === focused;
|
|
1340
|
-
return this.getActiveCompareValue() === cell.compareValue;
|
|
1486
|
+
return cell.compareValue === this.rovingCellValue();
|
|
1341
1487
|
}
|
|
1342
1488
|
/** Imperatively focuses the cell matching `compareValue` after the next render. */
|
|
1343
1489
|
focusCell(compareValue) {
|
|
@@ -1346,15 +1492,20 @@ class CalendarViewBase {
|
|
|
1346
1492
|
}
|
|
1347
1493
|
/** Focuses the cell that currently owns the roving cursor. */
|
|
1348
1494
|
focusActiveCell() {
|
|
1349
|
-
|
|
1495
|
+
// Read through `rovingCellValue` so a stale `focusedCellValue` cannot aim
|
|
1496
|
+
// focus at a cell that is no longer rendered — the same staleness that used
|
|
1497
|
+
// to empty the tab order also made this a silent no-op.
|
|
1498
|
+
const target = this.rovingCellValue();
|
|
1499
|
+
if (target === null)
|
|
1500
|
+
return;
|
|
1350
1501
|
this.focusCell(target);
|
|
1351
1502
|
}
|
|
1352
1503
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: CalendarViewBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1353
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: CalendarViewBase, isStandalone: true, inputs: { activeDate: { classPropertyName: "activeDate", publicName: "activeDate", isSignal: true, isRequired: true, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", 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 }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disabledDaysOfWeek: { classPropertyName: "disabledDaysOfWeek", publicName: "disabledDaysOfWeek", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, previewStart: { classPropertyName: "previewStart", publicName: "previewStart", isSignal: true, isRequired: false, transformFunction: null }, previewEnd: { classPropertyName: "previewEnd", publicName: "previewEnd", isSignal: true, isRequired: false, transformFunction: null }, invalidFlashDate: { classPropertyName: "invalidFlashDate", publicName: "invalidFlashDate", isSignal: true, isRequired: false, transformFunction: null }, multiSelectable: { classPropertyName: "multiSelectable", publicName: "multiSelectable", isSignal: true, isRequired: false, transformFunction: null }, readonlyGrid: { classPropertyName: "readonlyGrid", publicName: "readonlyGrid", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange", activeDateChange: "activeDateChange", previewChange: "previewChange" }, ngImport: i0 });
|
|
1504
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: CalendarViewBase, isStandalone: true, inputs: { activeDate: { classPropertyName: "activeDate", publicName: "activeDate", isSignal: true, isRequired: true, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", 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 }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disabledDaysOfWeek: { classPropertyName: "disabledDaysOfWeek", publicName: "disabledDaysOfWeek", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, previewStart: { classPropertyName: "previewStart", publicName: "previewStart", isSignal: true, isRequired: false, transformFunction: null }, previewEnd: { classPropertyName: "previewEnd", publicName: "previewEnd", isSignal: true, isRequired: false, transformFunction: null }, invalidFlashDate: { classPropertyName: "invalidFlashDate", publicName: "invalidFlashDate", isSignal: true, isRequired: false, transformFunction: null }, multiSelectable: { classPropertyName: "multiSelectable", publicName: "multiSelectable", isSignal: true, isRequired: false, transformFunction: null }, readonlyGrid: { classPropertyName: "readonlyGrid", publicName: "readonlyGrid", isSignal: true, isRequired: false, transformFunction: null }, disabledGrid: { classPropertyName: "disabledGrid", publicName: "disabledGrid", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange", activeDateChange: "activeDateChange", previewChange: "previewChange" }, ngImport: i0 });
|
|
1354
1505
|
}
|
|
1355
1506
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: CalendarViewBase, decorators: [{
|
|
1356
1507
|
type: Directive
|
|
1357
|
-
}], ctorParameters: () => [], propDecorators: { activeDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeDate", required: true }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disabledDaysOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDaysOfWeek", required: false }] }], dateClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateClass", required: false }] }], previewStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewStart", required: false }] }], previewEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewEnd", required: false }] }], invalidFlashDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidFlashDate", required: false }] }], multiSelectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSelectable", required: false }] }], readonlyGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonlyGrid", required: false }] }], cellTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplate", required: false }] }], selectedChange: [{ type: i0.Output, args: ["selectedChange"] }], activeDateChange: [{ type: i0.Output, args: ["activeDateChange"] }], previewChange: [{ type: i0.Output, args: ["previewChange"] }] } });
|
|
1508
|
+
}], ctorParameters: () => [], propDecorators: { activeDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeDate", required: true }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disabledDaysOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDaysOfWeek", required: false }] }], dateClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateClass", required: false }] }], previewStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewStart", required: false }] }], previewEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewEnd", required: false }] }], invalidFlashDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidFlashDate", required: false }] }], multiSelectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSelectable", required: false }] }], readonlyGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonlyGrid", required: false }] }], disabledGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledGrid", required: false }] }], cellTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplate", required: false }] }], selectedChange: [{ type: i0.Output, args: ["selectedChange"] }], activeDateChange: [{ type: i0.Output, args: ["activeDateChange"] }], previewChange: [{ type: i0.Output, args: ["previewChange"] }] } });
|
|
1358
1509
|
|
|
1359
1510
|
const TOTAL_CELLS = DAYS_PER_WEEK * WEEKS_PER_MONTH;
|
|
1360
1511
|
/**
|
|
@@ -1365,10 +1516,10 @@ class MonthViewComponent extends CalendarViewBase {
|
|
|
1365
1516
|
view = 'day';
|
|
1366
1517
|
cellComponents = viewChildren(CalendarCellComponent, /* @ts-ignore */
|
|
1367
1518
|
...(ngDevMode ? [{ debugName: "cellComponents" }] : /* istanbul ignore next */ []));
|
|
1368
|
-
/** Override first day of week (0=Sun, 1=Mon). */
|
|
1519
|
+
/** Override first day of week (0=Sun, 1=Mon). Defaults to `0` (Sunday). */
|
|
1369
1520
|
firstDayOfWeek = input(0, /* @ts-ignore */
|
|
1370
1521
|
...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
|
|
1371
|
-
/** Index within a multi-month row (0=left, 1+=right) — used by the orchestrator to disambiguate focus. */
|
|
1522
|
+
/** Index within a multi-month row (0=left, 1+=right) — used by the orchestrator to disambiguate focus. Defaults to `0`. */
|
|
1372
1523
|
gridIndex = input(0, /* @ts-ignore */
|
|
1373
1524
|
...(ngDevMode ? [{ debugName: "gridIndex" }] : /* istanbul ignore next */ []));
|
|
1374
1525
|
weekdayHeaders = computed(() => getWeekdayHeaders(this.dateAdapter, 'long', this.firstDayOfWeek()), /* @ts-ignore */
|
|
@@ -1392,6 +1543,7 @@ class MonthViewComponent extends CalendarViewBase {
|
|
|
1392
1543
|
const disabledDaysOfWeek = this.disabledDaysOfWeek();
|
|
1393
1544
|
const dateClass = this.dateClass();
|
|
1394
1545
|
const displayedMonth = this.displayMonth();
|
|
1546
|
+
const gridDisabled = this.disabledGrid();
|
|
1395
1547
|
const days = [];
|
|
1396
1548
|
for (let i = 0; i < TOTAL_CELLS; i++) {
|
|
1397
1549
|
const date = this.dateAdapter.addDays(startDate, i);
|
|
@@ -1403,7 +1555,8 @@ class MonthViewComponent extends CalendarViewBase {
|
|
|
1403
1555
|
value: date,
|
|
1404
1556
|
displayValue: String(dayOfMonth),
|
|
1405
1557
|
ariaLabel: this.dateAdapter.format(date, { dateTimeFormat: { dateStyle: 'full' } }),
|
|
1406
|
-
enabled: !
|
|
1558
|
+
enabled: !gridDisabled &&
|
|
1559
|
+
!isDateDisabled(date, minDate, maxDate, dateFilter, this.dateAdapter, disabledDates, disabledDaysOfWeek),
|
|
1407
1560
|
cssClasses: dateClass ? dateClass(date, this.view) : '',
|
|
1408
1561
|
compareValue,
|
|
1409
1562
|
});
|
|
@@ -1600,6 +1753,7 @@ class YearViewComponent extends CalendarViewBase {
|
|
|
1600
1753
|
const minDate = this.minDate();
|
|
1601
1754
|
const maxDate = this.maxDate();
|
|
1602
1755
|
const dateClass = this.dateClass();
|
|
1756
|
+
const gridDisabled = this.disabledGrid();
|
|
1603
1757
|
const months = [];
|
|
1604
1758
|
for (let m = 0; m < MONTHS_PER_YEAR; m++) {
|
|
1605
1759
|
const date = this.dateAdapter.create(year, m + 1, 1);
|
|
@@ -1608,7 +1762,7 @@ class YearViewComponent extends CalendarViewBase {
|
|
|
1608
1762
|
value: date,
|
|
1609
1763
|
displayValue: name,
|
|
1610
1764
|
ariaLabel: `${name} ${year}`,
|
|
1611
|
-
enabled: !isMonthDisabled(year, m, minDate, maxDate, this.dateAdapter),
|
|
1765
|
+
enabled: !gridDisabled && !isMonthDisabled(year, m, minDate, maxDate, this.dateAdapter),
|
|
1612
1766
|
cssClasses: dateClass ? dateClass(date, this.view) : '',
|
|
1613
1767
|
compareValue: m,
|
|
1614
1768
|
});
|
|
@@ -1827,6 +1981,7 @@ class YearsViewComponent extends CalendarViewBase {
|
|
|
1827
1981
|
const minDate = this.minDate();
|
|
1828
1982
|
const maxDate = this.maxDate();
|
|
1829
1983
|
const dateClass = this.dateClass();
|
|
1984
|
+
const gridDisabled = this.disabledGrid();
|
|
1830
1985
|
const years = [];
|
|
1831
1986
|
for (let i = 0; i < YEARS_PER_PAGE; i++) {
|
|
1832
1987
|
const year = start + i;
|
|
@@ -1836,7 +1991,7 @@ class YearsViewComponent extends CalendarViewBase {
|
|
|
1836
1991
|
value: date,
|
|
1837
1992
|
displayValue: label,
|
|
1838
1993
|
ariaLabel: label,
|
|
1839
|
-
enabled: !isYearDisabled(year, minDate, maxDate, this.dateAdapter),
|
|
1994
|
+
enabled: !gridDisabled && !isYearDisabled(year, minDate, maxDate, this.dateAdapter),
|
|
1840
1995
|
cssClasses: dateClass ? dateClass(date, this.view) : '',
|
|
1841
1996
|
compareValue: year,
|
|
1842
1997
|
});
|
|
@@ -2024,7 +2179,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2024
2179
|
}], propDecorators: { cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CalendarCellComponent), { isSignal: true }] }] } });
|
|
2025
2180
|
|
|
2026
2181
|
/**
|
|
2027
|
-
* Pluggable selection behaviour. Provide via `
|
|
2182
|
+
* Pluggable selection behaviour. Provide via `TW_CALENDAR_SELECTION_STRATEGY` to
|
|
2028
2183
|
* customise how clicks mutate the calendar's `selected` value.
|
|
2029
2184
|
*
|
|
2030
2185
|
* `D` is the date type understood by the active `DateAdapter`.
|
|
@@ -2034,14 +2189,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2034
2189
|
class CalendarSelectionStrategy {
|
|
2035
2190
|
}
|
|
2036
2191
|
/** Injection token for the active selection strategy. */
|
|
2037
|
-
const
|
|
2192
|
+
const TW_CALENDAR_SELECTION_STRATEGY = new InjectionToken('tw-calendar/SelectionStrategy');
|
|
2193
|
+
/**
|
|
2194
|
+
* @deprecated Renamed to {@link TW_CALENDAR_SELECTION_STRATEGY} for consistency
|
|
2195
|
+
* with every other ngx-tw injection token. This is the *same token instance*,
|
|
2196
|
+
* not a copy — providing under either name and injecting under the other
|
|
2197
|
+
* resolves — so the rename is safe to adopt incrementally. Removed in the next
|
|
2198
|
+
* major.
|
|
2199
|
+
*/
|
|
2200
|
+
const CALENDAR_SELECTION_STRATEGY = TW_CALENDAR_SELECTION_STRATEGY;
|
|
2038
2201
|
|
|
2039
2202
|
/**
|
|
2040
2203
|
* Single-date selection. Every click commits a new selection immediately.
|
|
2041
2204
|
* No preview range. `selected` has shape `D | null`.
|
|
2042
2205
|
*/
|
|
2043
2206
|
class SingleSelectionStrategy extends CalendarSelectionStrategy {
|
|
2044
|
-
dateAdapter = inject(
|
|
2207
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
2045
2208
|
select(date, _current) {
|
|
2046
2209
|
return { selection: date, isComplete: true };
|
|
2047
2210
|
}
|
|
@@ -2080,7 +2243,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2080
2243
|
* `selected` has shape `DateRange<D> | null`.
|
|
2081
2244
|
*/
|
|
2082
2245
|
class RangeSelectionStrategy extends CalendarSelectionStrategy {
|
|
2083
|
-
dateAdapter = inject(
|
|
2246
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
2084
2247
|
select(date, current) {
|
|
2085
2248
|
// No start yet, or the previous range is already complete — start over.
|
|
2086
2249
|
if (!current || (current.start && current.end)) {
|
|
@@ -2149,7 +2312,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2149
2312
|
* - `selected` has shape `D[]`.
|
|
2150
2313
|
*/
|
|
2151
2314
|
class MultiSelectionStrategy extends CalendarSelectionStrategy {
|
|
2152
|
-
dateAdapter = inject(
|
|
2315
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
2153
2316
|
select(date, current) {
|
|
2154
2317
|
const existing = current ?? [];
|
|
2155
2318
|
const index = existing.findIndex((d) => this.dateAdapter.sameDate(d, date));
|
|
@@ -2191,7 +2354,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2191
2354
|
* `selected` has shape `DateRange<D> | null`.
|
|
2192
2355
|
*/
|
|
2193
2356
|
class WeekSelectionStrategy extends CalendarSelectionStrategy {
|
|
2194
|
-
dateAdapter = inject(
|
|
2357
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
2195
2358
|
select(date, _current) {
|
|
2196
2359
|
return { selection: this.weekRange(date), isComplete: true };
|
|
2197
2360
|
}
|
|
@@ -2239,23 +2402,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2239
2402
|
|
|
2240
2403
|
/** Provides single-date selection (default behaviour). */
|
|
2241
2404
|
function provideSingleSelectionStrategy() {
|
|
2242
|
-
return { provide:
|
|
2405
|
+
return { provide: TW_CALENDAR_SELECTION_STRATEGY, useClass: SingleSelectionStrategy };
|
|
2243
2406
|
}
|
|
2244
2407
|
/** Provides two-click date-range selection. */
|
|
2245
2408
|
function provideRangeSelectionStrategy() {
|
|
2246
|
-
return { provide:
|
|
2409
|
+
return { provide: TW_CALENDAR_SELECTION_STRATEGY, useClass: RangeSelectionStrategy };
|
|
2247
2410
|
}
|
|
2248
2411
|
/** Provides toggle-based multi-date selection. */
|
|
2249
2412
|
function provideMultiSelectionStrategy() {
|
|
2250
|
-
return { provide:
|
|
2413
|
+
return { provide: TW_CALENDAR_SELECTION_STRATEGY, useClass: MultiSelectionStrategy };
|
|
2251
2414
|
}
|
|
2252
2415
|
/** Provides week-at-a-time selection. */
|
|
2253
2416
|
function provideWeekSelectionStrategy() {
|
|
2254
|
-
return { provide:
|
|
2417
|
+
return { provide: TW_CALENDAR_SELECTION_STRATEGY, useClass: WeekSelectionStrategy };
|
|
2255
2418
|
}
|
|
2256
2419
|
/** Provides an arbitrary custom selection strategy. */
|
|
2257
2420
|
function provideCalendarSelectionStrategy(strategy) {
|
|
2258
|
-
return { provide:
|
|
2421
|
+
return { provide: TW_CALENDAR_SELECTION_STRATEGY, useClass: strategy };
|
|
2259
2422
|
}
|
|
2260
2423
|
|
|
2261
2424
|
const calendarVariants = tv({
|
|
@@ -2272,8 +2435,22 @@ const calendarVariants = tv({
|
|
|
2272
2435
|
1: { months: '' },
|
|
2273
2436
|
2: { months: 'flex gap-3' },
|
|
2274
2437
|
},
|
|
2438
|
+
// Deliberately `opacity-50` WITHOUT `pointer-events-none`, which is the
|
|
2439
|
+
// pairing CLAUDE.md's disabled table otherwise prefers. Cells must keep
|
|
2440
|
+
// receiving mouse events: `calendar-cell.ts` dropped the native
|
|
2441
|
+
// `disabled` attribute precisely because browsers do not dispatch mouse
|
|
2442
|
+
// events on a natively-disabled button, which silently killed range
|
|
2443
|
+
// preview and made `focusButton()` a no-op. `pointer-events-none` here
|
|
2444
|
+
// reintroduces exactly that class of bug one level up. Activation is
|
|
2445
|
+
// already refused at three layers (the cell's `enabled` flag, the view
|
|
2446
|
+
// base's `onCellSelected`, and `onDateSelected`'s early return), so the
|
|
2447
|
+
// container needs no pointer suppression.
|
|
2448
|
+
disabled: {
|
|
2449
|
+
true: { root: 'opacity-50' },
|
|
2450
|
+
false: {},
|
|
2451
|
+
},
|
|
2275
2452
|
},
|
|
2276
|
-
defaultVariants: { bordered: true, columns: 1 },
|
|
2453
|
+
defaultVariants: { bordered: true, columns: 1, disabled: false },
|
|
2277
2454
|
}, { twMerge: true });
|
|
2278
2455
|
/**
|
|
2279
2456
|
* Main calendar orchestrator. Composes the header and view components
|
|
@@ -2289,7 +2466,7 @@ const calendarVariants = tv({
|
|
|
2289
2466
|
* it defaults to `CalendarValue<M, D>` so forms see raw adapter values).
|
|
2290
2467
|
*/
|
|
2291
2468
|
class CalendarComponent {
|
|
2292
|
-
dateAdapter = inject(
|
|
2469
|
+
dateAdapter = inject(TW_DATE_ADAPTER);
|
|
2293
2470
|
elementRef = inject((ElementRef));
|
|
2294
2471
|
injector = inject(Injector);
|
|
2295
2472
|
destroyRef = inject(DestroyRef);
|
|
@@ -2310,14 +2487,14 @@ class CalendarComponent {
|
|
|
2310
2487
|
* via `effectiveIntl()` (§19.4 per-field merge).
|
|
2311
2488
|
*/
|
|
2312
2489
|
injectedIntl = inject(CalendarIntl, { optional: true }) ?? new CalendarIntl();
|
|
2313
|
-
injectedStrategy = inject(
|
|
2490
|
+
injectedStrategy = inject(TW_CALENDAR_SELECTION_STRATEGY, {
|
|
2314
2491
|
optional: true,
|
|
2315
2492
|
});
|
|
2316
2493
|
monthViews = viewChildren(MonthViewComponent, /* @ts-ignore */
|
|
2317
2494
|
...(ngDevMode ? [{ debugName: "monthViews" }] : /* istanbul ignore next */ []));
|
|
2318
2495
|
/**
|
|
2319
2496
|
* Built-in strategies instantiated lazily in the host's injection context so
|
|
2320
|
-
* `inject(
|
|
2497
|
+
* `inject(TW_DATE_ADAPTER)` calls inside each strategy resolve. Range state will
|
|
2321
2498
|
* migrate into the orchestrator in Phase 6; single / multiple stay here as
|
|
2322
2499
|
* internals (not exported) via the spec's mode union.
|
|
2323
2500
|
*/
|
|
@@ -2329,13 +2506,14 @@ class CalendarComponent {
|
|
|
2329
2506
|
// ---------------------------------------------------------------------------
|
|
2330
2507
|
// Public inputs (§33.1)
|
|
2331
2508
|
// ---------------------------------------------------------------------------
|
|
2332
|
-
/** Selection mode (§5)
|
|
2509
|
+
/** Selection mode (§5), bound as `mode`. Changing this at runtime clears the value and emits `modeChange`. Defaults to `'single'`. */
|
|
2333
2510
|
modeInput = input('single', { ...(ngDevMode ? { debugName: "modeInput" } : /* istanbul ignore next */ {}), alias: 'mode' });
|
|
2334
2511
|
mode = linkedSignal(this.modeInput, /* @ts-ignore */
|
|
2335
2512
|
...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
2336
2513
|
/**
|
|
2337
|
-
* Consumer-bound value
|
|
2338
|
-
* `D[]` for multiple, `{ start; end }` for range.
|
|
2514
|
+
* Consumer-bound value, bound as `value`. Shape narrows by `M`: `D | null` for
|
|
2515
|
+
* single, `D[]` for multiple, `{ start; end }` for range. Defaults to `null`,
|
|
2516
|
+
* which reads as the empty selection in every mode.
|
|
2339
2517
|
*/
|
|
2340
2518
|
valueInput = input(null, { ...(ngDevMode ? { debugName: "valueInput" } : /* istanbul ignore next */ {}), alias: 'value' });
|
|
2341
2519
|
value = linkedSignal(this.valueInput, /* @ts-ignore */
|
|
@@ -2343,23 +2521,24 @@ class CalendarComponent {
|
|
|
2343
2521
|
/** Anchor date for the displayed view. Defaults to today on mount. */
|
|
2344
2522
|
startAt = input(null, /* @ts-ignore */
|
|
2345
2523
|
...(ngDevMode ? [{ debugName: "startAt" }] : /* istanbul ignore next */ []));
|
|
2346
|
-
/** Minimum selectable date. */
|
|
2524
|
+
/** Minimum selectable date. Defaults to `null` (no lower bound). */
|
|
2347
2525
|
minDate = input(null, /* @ts-ignore */
|
|
2348
2526
|
...(ngDevMode ? [{ debugName: "minDate" }] : /* istanbul ignore next */ []));
|
|
2349
|
-
/** Maximum selectable date. */
|
|
2527
|
+
/** Maximum selectable date. Defaults to `null` (no upper bound). */
|
|
2350
2528
|
maxDate = input(null, /* @ts-ignore */
|
|
2351
2529
|
...(ngDevMode ? [{ debugName: "maxDate" }] : /* istanbul ignore next */ []));
|
|
2352
|
-
/** Per-date predicate — return `false` to disable. */
|
|
2530
|
+
/** Per-date predicate — return `false` to disable. Defaults to `null` (every date passes). */
|
|
2353
2531
|
dateFilter = input(null, /* @ts-ignore */
|
|
2354
2532
|
...(ngDevMode ? [{ debugName: "dateFilter" }] : /* istanbul ignore next */ []));
|
|
2355
2533
|
/**
|
|
2356
2534
|
* Explicitly disabled dates (§10.1). Either an array (each entry compared via
|
|
2357
2535
|
* `adapter.sameDate`) or a predicate returning `true` for disabled dates.
|
|
2358
2536
|
* OR-combined with `dateFilter`, `disabledDaysOfWeek`, and `[minDate, maxDate]`.
|
|
2537
|
+
* Defaults to `null` (no explicitly disabled dates).
|
|
2359
2538
|
*/
|
|
2360
2539
|
disabledDates = input(null, /* @ts-ignore */
|
|
2361
2540
|
...(ngDevMode ? [{ debugName: "disabledDates" }] : /* istanbul ignore next */ []));
|
|
2362
|
-
/** Days of the week to disable (0=Sun … 6=Sat).
|
|
2541
|
+
/** Days of the week to disable (0=Sun … 6=Sat). Defaults to `[]` — no day-of-week disabling. */
|
|
2363
2542
|
disabledDaysOfWeek = input([], /* @ts-ignore */
|
|
2364
2543
|
...(ngDevMode ? [{ debugName: "disabledDaysOfWeek" }] : /* istanbul ignore next */ []));
|
|
2365
2544
|
/**
|
|
@@ -2368,17 +2547,17 @@ class CalendarComponent {
|
|
|
2368
2547
|
* useful for sharing a constraint preset across multiple calendars. Each field is
|
|
2369
2548
|
* optional. Individual inputs (`minDate`, `maxDate`, `disabledDates`,
|
|
2370
2549
|
* `disabledDaysOfWeek`, `dateFilter`) take precedence over fields here when both
|
|
2371
|
-
* are set non-null.
|
|
2550
|
+
* are set non-null. Defaults to `null` (no bundle; use the individual inputs).
|
|
2372
2551
|
*/
|
|
2373
2552
|
constraints = input(null, /* @ts-ignore */
|
|
2374
2553
|
...(ngDevMode ? [{ debugName: "constraints" }] : /* istanbul ignore next */ []));
|
|
2375
|
-
/** Minimum range length in days, inclusive (`mode: 'range'` only). `null`
|
|
2554
|
+
/** Minimum range length in days, inclusive (`mode: 'range'` only). Defaults to `null` — no minimum. */
|
|
2376
2555
|
minRangeLength = input(null, /* @ts-ignore */
|
|
2377
2556
|
...(ngDevMode ? [{ debugName: "minRangeLength" }] : /* istanbul ignore next */ []));
|
|
2378
|
-
/** Maximum range length in days, inclusive (`mode: 'range'` only). `null`
|
|
2557
|
+
/** Maximum range length in days, inclusive (`mode: 'range'` only). Defaults to `null` — no maximum. */
|
|
2379
2558
|
maxRangeLength = input(null, /* @ts-ignore */
|
|
2380
2559
|
...(ngDevMode ? [{ debugName: "maxRangeLength" }] : /* istanbul ignore next */ []));
|
|
2381
|
-
/** Maximum number of selections in `mode: 'multiple'`. `null`
|
|
2560
|
+
/** Maximum number of selections in `mode: 'multiple'`. Defaults to `null` — unlimited. */
|
|
2382
2561
|
maxSelections = input(null, /* @ts-ignore */
|
|
2383
2562
|
...(ngDevMode ? [{ debugName: "maxSelections" }] : /* istanbul ignore next */ []));
|
|
2384
2563
|
/**
|
|
@@ -2391,10 +2570,41 @@ class CalendarComponent {
|
|
|
2391
2570
|
/**
|
|
2392
2571
|
* IDREF list for the form-error live region (§28.3). When set, the calendar
|
|
2393
2572
|
* root carries `aria-describedby="<value>"` so screen readers read consumer-
|
|
2394
|
-
* rendered error messages alongside the focused cell announcement.
|
|
2573
|
+
* rendered error messages alongside the focused cell announcement. Defaults to
|
|
2574
|
+
* `null` (no error ids are contributed).
|
|
2575
|
+
*
|
|
2576
|
+
* @deprecated Superseded by the plain `aria-describedby` attribute, which now
|
|
2577
|
+
* feeds {@link ariaDescribedby}. Both are merged — error ids first — so an
|
|
2578
|
+
* existing `[errorAriaDescribedBy]` binding keeps working; it will be removed
|
|
2579
|
+
* in a future major.
|
|
2395
2580
|
*/
|
|
2396
2581
|
errorAriaDescribedBy = input(null, /* @ts-ignore */
|
|
2397
2582
|
...(ngDevMode ? [{ debugName: "errorAriaDescribedBy" }] : /* istanbul ignore next */ []));
|
|
2583
|
+
/**
|
|
2584
|
+
* ID of an external element that describes the calendar, supplied as the plain
|
|
2585
|
+
* `aria-describedby` attribute. Merged with {@link errorAriaDescribedBy} —
|
|
2586
|
+
* error ids are listed first so assistive tech announces them before the
|
|
2587
|
+
* general description. Defaults to `null`.
|
|
2588
|
+
*/
|
|
2589
|
+
ariaDescribedby = input(null, { ...(ngDevMode ? { debugName: "ariaDescribedby" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
2590
|
+
/**
|
|
2591
|
+
* Merged `aria-describedby` IDREF list: error ids from
|
|
2592
|
+
* {@link errorAriaDescribedBy} first, then the consumer's `aria-describedby`.
|
|
2593
|
+
* Mirrors `checkbox`'s `effectiveAriaDescribedby()`.
|
|
2594
|
+
*
|
|
2595
|
+
* @internal
|
|
2596
|
+
*/
|
|
2597
|
+
effectiveAriaDescribedby = computed(() => {
|
|
2598
|
+
const merged = [];
|
|
2599
|
+
for (const source of [this.errorAriaDescribedBy(), this.ariaDescribedby()]) {
|
|
2600
|
+
if (!source)
|
|
2601
|
+
continue;
|
|
2602
|
+
for (const id of source.split(/\s+/).filter(Boolean))
|
|
2603
|
+
merged.push(id);
|
|
2604
|
+
}
|
|
2605
|
+
return merged.length ? merged.join(' ') : undefined;
|
|
2606
|
+
}, /* @ts-ignore */
|
|
2607
|
+
...(ngDevMode ? [{ debugName: "effectiveAriaDescribedby" }] : /* istanbul ignore next */ []));
|
|
2398
2608
|
/**
|
|
2399
2609
|
* How `mode: 'range'` reacts to a click after a complete range (§21.2):
|
|
2400
2610
|
* - `'restart'` (default): start a new range with the clicked cell, emit `selectionRestart`.
|
|
@@ -2410,37 +2620,37 @@ class CalendarComponent {
|
|
|
2410
2620
|
*/
|
|
2411
2621
|
rangeBehavior = input({}, /* @ts-ignore */
|
|
2412
2622
|
...(ngDevMode ? [{ debugName: "rangeBehavior" }] : /* istanbul ignore next */ []));
|
|
2413
|
-
/** Function producing per-cell CSS classes. */
|
|
2623
|
+
/** Function producing per-cell CSS classes, appended to the cell button. Defaults to `null` (no extra classes). */
|
|
2414
2624
|
dateClass = input(null, /* @ts-ignore */
|
|
2415
2625
|
...(ngDevMode ? [{ debugName: "dateClass" }] : /* istanbul ignore next */ []));
|
|
2416
|
-
/** When `true`, the calendar renders with a border and a soft shadow. */
|
|
2626
|
+
/** When `true`, the calendar renders with a border and a soft shadow. Defaults to `true` — an embedded calendar reads as a bordered panel; the special case is the borderless variant. */
|
|
2417
2627
|
bordered = input(true, /* @ts-ignore */
|
|
2418
2628
|
...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
|
|
2419
2629
|
/** Which view opens first. Defaults to `'day'`. Phase 8 will derive the default from `rangeGranularity`. */
|
|
2420
2630
|
startView = input('day', /* @ts-ignore */
|
|
2421
2631
|
...(ngDevMode ? [{ debugName: "startView" }] : /* istanbul ignore next */ []));
|
|
2422
|
-
/** Override first day of week (0=Sun, 1=Mon).
|
|
2632
|
+
/** Override first day of week (0=Sun, 1=Mon). Defaults to `null` — falls back to the adapter's locale default. */
|
|
2423
2633
|
firstDayOfWeek = input(null, /* @ts-ignore */
|
|
2424
2634
|
...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : /* istanbul ignore next */ []));
|
|
2425
2635
|
/**
|
|
2426
2636
|
* Number of months to display side-by-side (1 or 2). Phase 9 replaces this with a
|
|
2427
|
-
* full `numberOfMonths: 1..12+` surface (§23).
|
|
2637
|
+
* full `numberOfMonths: 1..12+` surface (§23). Defaults to `1`.
|
|
2428
2638
|
*/
|
|
2429
2639
|
monthColumns = input(1, /* @ts-ignore */
|
|
2430
2640
|
...(ngDevMode ? [{ debugName: "monthColumns" }] : /* istanbul ignore next */ []));
|
|
2431
|
-
/** Disabled state. Merged with any `setDisabledState` call from a bound form control via `effectiveDisabled`. */
|
|
2641
|
+
/** Disabled state. Merged with any `setDisabledState` call from a bound form control via `effectiveDisabled`. Defaults to `false`. */
|
|
2432
2642
|
disabled = input(false, /* @ts-ignore */
|
|
2433
2643
|
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
2434
|
-
/** Read-only state (§33.1). When `true`, focus and keyboard navigation still work but selections cannot be committed. */
|
|
2644
|
+
/** Read-only state (§33.1). When `true`, focus and keyboard navigation still work but selections cannot be committed. Defaults to `false`. */
|
|
2435
2645
|
readonly = input(false, /* @ts-ignore */
|
|
2436
2646
|
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
2437
2647
|
/** How a form reset restores internal state (§6.5). `'full'` (default) also restores view + active-date; `'value-only'` clears the draft but leaves navigation where the user left it. */
|
|
2438
2648
|
resetBehavior = input('full', /* @ts-ignore */
|
|
2439
2649
|
...(ngDevMode ? [{ debugName: "resetBehavior" }] : /* istanbul ignore next */ []));
|
|
2440
|
-
/** Optional cell-content template. */
|
|
2650
|
+
/** Optional cell-content template, rendered inside each cell button with `{ $implicit: CalendarCell<D> }`. Defaults to `null` (cells render their own display value). */
|
|
2441
2651
|
cellTemplate = input(null, /* @ts-ignore */
|
|
2442
2652
|
...(ngDevMode ? [{ debugName: "cellTemplate" }] : /* istanbul ignore next */ []));
|
|
2443
|
-
/** Per-instance locale override.
|
|
2653
|
+
/** Per-instance locale override. Defaults to `null` — falls back to Angular's `LOCALE_ID` (§19.1). */
|
|
2444
2654
|
locale = input(null, /* @ts-ignore */
|
|
2445
2655
|
...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
2446
2656
|
/**
|
|
@@ -2794,7 +3004,8 @@ class CalendarComponent {
|
|
|
2794
3004
|
/**
|
|
2795
3005
|
* Effective `CalendarIntl` resolved per-field over the DI default (§19.4).
|
|
2796
3006
|
* The injected default is the base; the `intl` input overrides individual
|
|
2797
|
-
* fields. Unspecified fields fall through to English defaults
|
|
3007
|
+
* fields. Unspecified fields fall through to English defaults — and so do
|
|
3008
|
+
* fields the consumer set explicitly to `undefined`.
|
|
2798
3009
|
*/
|
|
2799
3010
|
effectiveIntl = computed(() => {
|
|
2800
3011
|
const override = this.intl();
|
|
@@ -2803,7 +3014,14 @@ class CalendarComponent {
|
|
|
2803
3014
|
// Prototype copy preserves bound methods; shallow per-field overlay matches
|
|
2804
3015
|
// the spec's per-field merge semantics.
|
|
2805
3016
|
const merged = Object.create(Object.getPrototypeOf(this.injectedIntl));
|
|
2806
|
-
Object.assign
|
|
3017
|
+
// Drop explicitly-`undefined` keys first. `Object.assign` copies own
|
|
3018
|
+
// enumerable properties *including* ones whose value is `undefined`, so
|
|
3019
|
+
// `[intl]="{ monthViewLabel: bundle['x'] }"` with a missing key would blank
|
|
3020
|
+
// the default rather than fall through to it — and `viewSwitched()` calls
|
|
3021
|
+
// `.replace()` on that field directly, throwing on the next view switch.
|
|
3022
|
+
// Same guard as `provideCalendarIntl`.
|
|
3023
|
+
const overrides = Object.fromEntries(Object.entries(override).filter(([, value]) => value !== undefined));
|
|
3024
|
+
Object.assign(merged, this.injectedIntl, overrides);
|
|
2807
3025
|
return merged;
|
|
2808
3026
|
}, /* @ts-ignore */
|
|
2809
3027
|
...(ngDevMode ? [{ debugName: "effectiveIntl" }] : /* istanbul ignore next */ []));
|
|
@@ -2903,6 +3121,7 @@ class CalendarComponent {
|
|
|
2903
3121
|
variantResult = computed(() => calendarVariants({
|
|
2904
3122
|
bordered: this.bordered(),
|
|
2905
3123
|
columns: (this.effectiveMonthColumns() >= 2 ? 2 : 1),
|
|
3124
|
+
disabled: this.effectiveDisabled(),
|
|
2906
3125
|
}), /* @ts-ignore */
|
|
2907
3126
|
...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
|
|
2908
3127
|
/** @internal */
|
|
@@ -3670,7 +3889,7 @@ class CalendarComponent {
|
|
|
3670
3889
|
return this.dateAdapter.format(date, { dateTimeFormat: { dateStyle: 'full' } });
|
|
3671
3890
|
}
|
|
3672
3891
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3673
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: CalendarComponent, isStandalone: true, selector: "tw-calendar", inputs: { modeInput: { classPropertyName: "modeInput", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disabledDaysOfWeek: { classPropertyName: "disabledDaysOfWeek", publicName: "disabledDaysOfWeek", isSignal: true, isRequired: false, transformFunction: null }, constraints: { classPropertyName: "constraints", publicName: "constraints", isSignal: true, isRequired: false, transformFunction: null }, minRangeLength: { classPropertyName: "minRangeLength", publicName: "minRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxRangeLength: { classPropertyName: "maxRangeLength", publicName: "maxRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxSelections: { classPropertyName: "maxSelections", publicName: "maxSelections", isSignal: true, isRequired: false, transformFunction: null }, maxSelectionBehavior: { classPropertyName: "maxSelectionBehavior", publicName: "maxSelectionBehavior", isSignal: true, isRequired: false, transformFunction: null }, errorAriaDescribedBy: { classPropertyName: "errorAriaDescribedBy", publicName: "errorAriaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, rangeClickBehavior: { classPropertyName: "rangeClickBehavior", publicName: "rangeClickBehavior", isSignal: true, isRequired: false, transformFunction: null }, rangeBehavior: { classPropertyName: "rangeBehavior", publicName: "rangeBehavior", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, monthColumns: { classPropertyName: "monthColumns", publicName: "monthColumns", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, resetBehavior: { classPropertyName: "resetBehavior", publicName: "resetBehavior", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, intl: { classPropertyName: "intl", publicName: "intl", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", selectionStart: "selectionStart", rangePreview: "rangePreview", selectionComplete: "selectionComplete", selectionRestart: "selectionRestart", selectionCleared: "selectionCleared", selectionLimitReached: "selectionLimitReached", presetChange: "presetChange", viewChange: "viewChange", activeDateChange: "activeDateChange", monthChange: "monthChange", yearChange: "yearChange", cellClick: "cellClick", cellHover: "cellHover", modeChange: "modeChange" }, host: { listeners: { "focusout": "onBlur($event)" }, properties: { "attr.aria-disabled": "effectiveDisabled() || null", "attr.aria-readonly": "effectiveReadonly() || null", "attr.aria-describedby": "
|
|
3892
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: CalendarComponent, isStandalone: true, selector: "tw-calendar", inputs: { modeInput: { classPropertyName: "modeInput", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null }, disabledDaysOfWeek: { classPropertyName: "disabledDaysOfWeek", publicName: "disabledDaysOfWeek", isSignal: true, isRequired: false, transformFunction: null }, constraints: { classPropertyName: "constraints", publicName: "constraints", isSignal: true, isRequired: false, transformFunction: null }, minRangeLength: { classPropertyName: "minRangeLength", publicName: "minRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxRangeLength: { classPropertyName: "maxRangeLength", publicName: "maxRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxSelections: { classPropertyName: "maxSelections", publicName: "maxSelections", isSignal: true, isRequired: false, transformFunction: null }, maxSelectionBehavior: { classPropertyName: "maxSelectionBehavior", publicName: "maxSelectionBehavior", isSignal: true, isRequired: false, transformFunction: null }, errorAriaDescribedBy: { classPropertyName: "errorAriaDescribedBy", publicName: "errorAriaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, rangeClickBehavior: { classPropertyName: "rangeClickBehavior", publicName: "rangeClickBehavior", isSignal: true, isRequired: false, transformFunction: null }, rangeBehavior: { classPropertyName: "rangeBehavior", publicName: "rangeBehavior", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, monthColumns: { classPropertyName: "monthColumns", publicName: "monthColumns", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, resetBehavior: { classPropertyName: "resetBehavior", publicName: "resetBehavior", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, intl: { classPropertyName: "intl", publicName: "intl", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", selectionStart: "selectionStart", rangePreview: "rangePreview", selectionComplete: "selectionComplete", selectionRestart: "selectionRestart", selectionCleared: "selectionCleared", selectionLimitReached: "selectionLimitReached", presetChange: "presetChange", viewChange: "viewChange", activeDateChange: "activeDateChange", monthChange: "monthChange", yearChange: "yearChange", cellClick: "cellClick", cellHover: "cellHover", modeChange: "modeChange" }, host: { listeners: { "focusout": "onBlur($event)" }, properties: { "attr.aria-disabled": "effectiveDisabled() || null", "attr.aria-readonly": "effectiveReadonly() || null", "attr.aria-describedby": "effectiveAriaDescribedby() || null" }, classAttribute: "block" }, providers: [
|
|
3674
3893
|
{
|
|
3675
3894
|
provide: NG_VALUE_ACCESSOR,
|
|
3676
3895
|
useExisting: forwardRef(() => CalendarComponent),
|
|
@@ -3692,9 +3911,9 @@ class CalendarComponent {
|
|
|
3692
3911
|
[periodAriaLabel]="periodAriaLabel()"
|
|
3693
3912
|
[prevAriaLabel]="prevAriaLabel()"
|
|
3694
3913
|
[nextAriaLabel]="nextAriaLabel()"
|
|
3695
|
-
[prevDisabled]="prevDisabled()"
|
|
3696
|
-
[nextDisabled]="nextDisabled()"
|
|
3697
|
-
[canSwitchView]="viewState() !== 'year'"
|
|
3914
|
+
[prevDisabled]="prevDisabled() || effectiveDisabled()"
|
|
3915
|
+
[nextDisabled]="nextDisabled() || effectiveDisabled()"
|
|
3916
|
+
[canSwitchView]="viewState() !== 'year' && !effectiveDisabled()"
|
|
3698
3917
|
(prevClicked)="onPrevClicked()"
|
|
3699
3918
|
(nextClicked)="onNextClicked()"
|
|
3700
3919
|
(periodClicked)="onPeriodClicked()"
|
|
@@ -3702,6 +3921,44 @@ class CalendarComponent {
|
|
|
3702
3921
|
|
|
3703
3922
|
<ng-content select="[twCalendarPresets]" />
|
|
3704
3923
|
|
|
3924
|
+
<!--
|
|
3925
|
+
View region — height-pinned so day → month → year switching never
|
|
3926
|
+
resizes the panel vertically. The root is inline-block, so without this
|
|
3927
|
+
the three views rendered 252 / 108 / 216 tall and the popup jumped on
|
|
3928
|
+
every view switch.
|
|
3929
|
+
|
|
3930
|
+
min-h-63 = 252px = the day grid, the tallest view, which always renders
|
|
3931
|
+
a fixed 6 weeks: one h-9 weekday header row + 6 h-9 week rows. It is a
|
|
3932
|
+
min-*, never h-*, so a taller consumer cell template can still grow.
|
|
3933
|
+
The number is derived from the cell geometry in calendar-cell.ts —
|
|
3934
|
+
change a cell's h-* and this has to be recomputed, or the tallest view
|
|
3935
|
+
starts overflowing it.
|
|
3936
|
+
|
|
3937
|
+
Stock spacing utility on purpose: a --width-calendar-* theme token was
|
|
3938
|
+
tried and deleted, because tailwind-merge cannot collapse custom-token
|
|
3939
|
+
classes and consumer overrides silently stop winning
|
|
3940
|
+
(docs/vertical-rhythm.md section 1).
|
|
3941
|
+
|
|
3942
|
+
Width is NOT pinned either, and no longer needs to be. All three views
|
|
3943
|
+
compute to the same 252px intrinsic width, so the panel holds one width
|
|
3944
|
+
across view switches on its own: the day grid is grid-cols-7 gap-0 at
|
|
3945
|
+
7 x 36, and the month and year grids are grid-cols-4 gap-1 at 4 x 60
|
|
3946
|
+
plus 3 x 4. The cell widths that produce this live in the view variant
|
|
3947
|
+
in calendar-cell.ts. They used to measure 252 / 268 / 236.
|
|
3948
|
+
|
|
3949
|
+
A min-w on this wrapper was the rejected alternative: it redistributes
|
|
3950
|
+
the day grid's grid-cols-7 into fractional columns (268/7 = 38.28px)
|
|
3951
|
+
while the day button stays 36px, which pushes the range wrapper's
|
|
3952
|
+
rounded-l-full / rounded-r-full cap ~1px past the selected endpoint pill
|
|
3953
|
+
at every range boundary. Equalizing through the month and year cell
|
|
3954
|
+
widths instead leaves the day view untouched, so the pill and its
|
|
3955
|
+
wrapper still coincide exactly.
|
|
3956
|
+
|
|
3957
|
+
Still unequal in 2-column mode: the day case renders two month grids
|
|
3958
|
+
side by side, 2 x 252 plus a gap-3, while the month and year views
|
|
3959
|
+
render a single grid. Cell widths cannot express that.
|
|
3960
|
+
-->
|
|
3961
|
+
<div class="min-h-63">
|
|
3705
3962
|
@switch (viewState()) {
|
|
3706
3963
|
@case ('day') {
|
|
3707
3964
|
<div [class]="monthsClasses()">
|
|
@@ -3722,6 +3979,7 @@ class CalendarComponent {
|
|
|
3722
3979
|
[gridIndex]="0"
|
|
3723
3980
|
[multiSelectable]="multiSelectable()"
|
|
3724
3981
|
[readonlyGrid]="effectiveReadonly()"
|
|
3982
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3725
3983
|
(selectedChange)="onDateSelected($event)"
|
|
3726
3984
|
(activeDateChange)="onActiveDateChange($event, 0)"
|
|
3727
3985
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3744,6 +4002,7 @@ class CalendarComponent {
|
|
|
3744
4002
|
[gridIndex]="1"
|
|
3745
4003
|
[multiSelectable]="multiSelectable()"
|
|
3746
4004
|
[readonlyGrid]="effectiveReadonly()"
|
|
4005
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3747
4006
|
(selectedChange)="onDateSelected($event)"
|
|
3748
4007
|
(activeDateChange)="onActiveDateChange($event, 1)"
|
|
3749
4008
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3763,6 +4022,7 @@ class CalendarComponent {
|
|
|
3763
4022
|
[previewEnd]="previewRange()?.end ?? null"
|
|
3764
4023
|
[multiSelectable]="multiSelectable()"
|
|
3765
4024
|
[readonlyGrid]="effectiveReadonly()"
|
|
4025
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3766
4026
|
(selectedChange)="onMonthSelected($event)"
|
|
3767
4027
|
(activeDateChange)="onActiveDateChange($event)"
|
|
3768
4028
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3780,12 +4040,14 @@ class CalendarComponent {
|
|
|
3780
4040
|
[previewEnd]="previewRange()?.end ?? null"
|
|
3781
4041
|
[multiSelectable]="multiSelectable()"
|
|
3782
4042
|
[readonlyGrid]="effectiveReadonly()"
|
|
4043
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3783
4044
|
(selectedChange)="onYearSelected($event)"
|
|
3784
4045
|
(activeDateChange)="onActiveDateChange($event)"
|
|
3785
4046
|
(previewChange)="onPreviewChange($event)"
|
|
3786
4047
|
/>
|
|
3787
4048
|
}
|
|
3788
4049
|
}
|
|
4050
|
+
</div>
|
|
3789
4051
|
</div>
|
|
3790
4052
|
`, isInline: true, dependencies: [{ kind: "component", type: CalendarHeaderComponent, selector: "tw-calendar-header", inputs: ["periodLabel", "periodAriaLabel", "prevAriaLabel", "nextAriaLabel", "prevDisabled", "nextDisabled", "canSwitchView"], outputs: ["prevClicked", "nextClicked", "periodClicked"] }, { kind: "component", type: MonthViewComponent, selector: "tw-calendar-month-view", inputs: ["firstDayOfWeek", "gridIndex"] }, { kind: "component", type: YearViewComponent, selector: "tw-calendar-year-view" }, { kind: "component", type: YearsViewComponent, selector: "tw-calendar-years-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3791
4053
|
}
|
|
@@ -3816,7 +4078,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3816
4078
|
class: 'block',
|
|
3817
4079
|
'[attr.aria-disabled]': 'effectiveDisabled() || null',
|
|
3818
4080
|
'[attr.aria-readonly]': 'effectiveReadonly() || null',
|
|
3819
|
-
'[attr.aria-describedby]': '
|
|
4081
|
+
'[attr.aria-describedby]': 'effectiveAriaDescribedby() || null',
|
|
3820
4082
|
'(focusout)': 'onBlur($event)',
|
|
3821
4083
|
},
|
|
3822
4084
|
template: `
|
|
@@ -3830,9 +4092,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3830
4092
|
[periodAriaLabel]="periodAriaLabel()"
|
|
3831
4093
|
[prevAriaLabel]="prevAriaLabel()"
|
|
3832
4094
|
[nextAriaLabel]="nextAriaLabel()"
|
|
3833
|
-
[prevDisabled]="prevDisabled()"
|
|
3834
|
-
[nextDisabled]="nextDisabled()"
|
|
3835
|
-
[canSwitchView]="viewState() !== 'year'"
|
|
4095
|
+
[prevDisabled]="prevDisabled() || effectiveDisabled()"
|
|
4096
|
+
[nextDisabled]="nextDisabled() || effectiveDisabled()"
|
|
4097
|
+
[canSwitchView]="viewState() !== 'year' && !effectiveDisabled()"
|
|
3836
4098
|
(prevClicked)="onPrevClicked()"
|
|
3837
4099
|
(nextClicked)="onNextClicked()"
|
|
3838
4100
|
(periodClicked)="onPeriodClicked()"
|
|
@@ -3840,6 +4102,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3840
4102
|
|
|
3841
4103
|
<ng-content select="[twCalendarPresets]" />
|
|
3842
4104
|
|
|
4105
|
+
<!--
|
|
4106
|
+
View region — height-pinned so day → month → year switching never
|
|
4107
|
+
resizes the panel vertically. The root is inline-block, so without this
|
|
4108
|
+
the three views rendered 252 / 108 / 216 tall and the popup jumped on
|
|
4109
|
+
every view switch.
|
|
4110
|
+
|
|
4111
|
+
min-h-63 = 252px = the day grid, the tallest view, which always renders
|
|
4112
|
+
a fixed 6 weeks: one h-9 weekday header row + 6 h-9 week rows. It is a
|
|
4113
|
+
min-*, never h-*, so a taller consumer cell template can still grow.
|
|
4114
|
+
The number is derived from the cell geometry in calendar-cell.ts —
|
|
4115
|
+
change a cell's h-* and this has to be recomputed, or the tallest view
|
|
4116
|
+
starts overflowing it.
|
|
4117
|
+
|
|
4118
|
+
Stock spacing utility on purpose: a --width-calendar-* theme token was
|
|
4119
|
+
tried and deleted, because tailwind-merge cannot collapse custom-token
|
|
4120
|
+
classes and consumer overrides silently stop winning
|
|
4121
|
+
(docs/vertical-rhythm.md section 1).
|
|
4122
|
+
|
|
4123
|
+
Width is NOT pinned either, and no longer needs to be. All three views
|
|
4124
|
+
compute to the same 252px intrinsic width, so the panel holds one width
|
|
4125
|
+
across view switches on its own: the day grid is grid-cols-7 gap-0 at
|
|
4126
|
+
7 x 36, and the month and year grids are grid-cols-4 gap-1 at 4 x 60
|
|
4127
|
+
plus 3 x 4. The cell widths that produce this live in the view variant
|
|
4128
|
+
in calendar-cell.ts. They used to measure 252 / 268 / 236.
|
|
4129
|
+
|
|
4130
|
+
A min-w on this wrapper was the rejected alternative: it redistributes
|
|
4131
|
+
the day grid's grid-cols-7 into fractional columns (268/7 = 38.28px)
|
|
4132
|
+
while the day button stays 36px, which pushes the range wrapper's
|
|
4133
|
+
rounded-l-full / rounded-r-full cap ~1px past the selected endpoint pill
|
|
4134
|
+
at every range boundary. Equalizing through the month and year cell
|
|
4135
|
+
widths instead leaves the day view untouched, so the pill and its
|
|
4136
|
+
wrapper still coincide exactly.
|
|
4137
|
+
|
|
4138
|
+
Still unequal in 2-column mode: the day case renders two month grids
|
|
4139
|
+
side by side, 2 x 252 plus a gap-3, while the month and year views
|
|
4140
|
+
render a single grid. Cell widths cannot express that.
|
|
4141
|
+
-->
|
|
4142
|
+
<div class="min-h-63">
|
|
3843
4143
|
@switch (viewState()) {
|
|
3844
4144
|
@case ('day') {
|
|
3845
4145
|
<div [class]="monthsClasses()">
|
|
@@ -3860,6 +4160,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3860
4160
|
[gridIndex]="0"
|
|
3861
4161
|
[multiSelectable]="multiSelectable()"
|
|
3862
4162
|
[readonlyGrid]="effectiveReadonly()"
|
|
4163
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3863
4164
|
(selectedChange)="onDateSelected($event)"
|
|
3864
4165
|
(activeDateChange)="onActiveDateChange($event, 0)"
|
|
3865
4166
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3882,6 +4183,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3882
4183
|
[gridIndex]="1"
|
|
3883
4184
|
[multiSelectable]="multiSelectable()"
|
|
3884
4185
|
[readonlyGrid]="effectiveReadonly()"
|
|
4186
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3885
4187
|
(selectedChange)="onDateSelected($event)"
|
|
3886
4188
|
(activeDateChange)="onActiveDateChange($event, 1)"
|
|
3887
4189
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3901,6 +4203,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3901
4203
|
[previewEnd]="previewRange()?.end ?? null"
|
|
3902
4204
|
[multiSelectable]="multiSelectable()"
|
|
3903
4205
|
[readonlyGrid]="effectiveReadonly()"
|
|
4206
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3904
4207
|
(selectedChange)="onMonthSelected($event)"
|
|
3905
4208
|
(activeDateChange)="onActiveDateChange($event)"
|
|
3906
4209
|
(previewChange)="onPreviewChange($event)"
|
|
@@ -3918,16 +4221,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3918
4221
|
[previewEnd]="previewRange()?.end ?? null"
|
|
3919
4222
|
[multiSelectable]="multiSelectable()"
|
|
3920
4223
|
[readonlyGrid]="effectiveReadonly()"
|
|
4224
|
+
[disabledGrid]="effectiveDisabled()"
|
|
3921
4225
|
(selectedChange)="onYearSelected($event)"
|
|
3922
4226
|
(activeDateChange)="onActiveDateChange($event)"
|
|
3923
4227
|
(previewChange)="onPreviewChange($event)"
|
|
3924
4228
|
/>
|
|
3925
4229
|
}
|
|
3926
4230
|
}
|
|
4231
|
+
</div>
|
|
3927
4232
|
</div>
|
|
3928
4233
|
`,
|
|
3929
4234
|
}]
|
|
3930
|
-
}], ctorParameters: () => [], propDecorators: { monthViews: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => MonthViewComponent), { isSignal: true }] }], modeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disabledDaysOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDaysOfWeek", required: false }] }], constraints: [{ type: i0.Input, args: [{ isSignal: true, alias: "constraints", required: false }] }], minRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRangeLength", required: false }] }], maxRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRangeLength", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], maxSelectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelectionBehavior", required: false }] }], errorAriaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorAriaDescribedBy", required: false }] }], rangeClickBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeClickBehavior", required: false }] }], rangeBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeBehavior", required: false }] }], dateClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateClass", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], monthColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthColumns", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], resetBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetBehavior", required: false }] }], cellTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplate", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], intl: [{ type: i0.Input, args: [{ isSignal: true, alias: "intl", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], selectionStart: [{ type: i0.Output, args: ["selectionStart"] }], rangePreview: [{ type: i0.Output, args: ["rangePreview"] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], selectionRestart: [{ type: i0.Output, args: ["selectionRestart"] }], selectionCleared: [{ type: i0.Output, args: ["selectionCleared"] }], selectionLimitReached: [{ type: i0.Output, args: ["selectionLimitReached"] }], presetChange: [{ type: i0.Output, args: ["presetChange"] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }], activeDateChange: [{ type: i0.Output, args: ["activeDateChange"] }], monthChange: [{ type: i0.Output, args: ["monthChange"] }], yearChange: [{ type: i0.Output, args: ["yearChange"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], cellHover: [{ type: i0.Output, args: ["cellHover"] }], modeChange: [{ type: i0.Output, args: ["modeChange"] }] } });
|
|
4235
|
+
}], ctorParameters: () => [], propDecorators: { monthViews: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => MonthViewComponent), { isSignal: true }] }], modeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], disabledDates: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDates", required: false }] }], disabledDaysOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDaysOfWeek", required: false }] }], constraints: [{ type: i0.Input, args: [{ isSignal: true, alias: "constraints", required: false }] }], minRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRangeLength", required: false }] }], maxRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRangeLength", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], maxSelectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelectionBehavior", required: false }] }], errorAriaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorAriaDescribedBy", required: false }] }], ariaDescribedby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], rangeClickBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeClickBehavior", required: false }] }], rangeBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeBehavior", required: false }] }], dateClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateClass", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], monthColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "monthColumns", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], resetBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetBehavior", required: false }] }], cellTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplate", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], intl: [{ type: i0.Input, args: [{ isSignal: true, alias: "intl", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], selectionStart: [{ type: i0.Output, args: ["selectionStart"] }], rangePreview: [{ type: i0.Output, args: ["rangePreview"] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], selectionRestart: [{ type: i0.Output, args: ["selectionRestart"] }], selectionCleared: [{ type: i0.Output, args: ["selectionCleared"] }], selectionLimitReached: [{ type: i0.Output, args: ["selectionLimitReached"] }], presetChange: [{ type: i0.Output, args: ["presetChange"] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }], activeDateChange: [{ type: i0.Output, args: ["activeDateChange"] }], monthChange: [{ type: i0.Output, args: ["monthChange"] }], yearChange: [{ type: i0.Output, args: ["yearChange"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], cellHover: [{ type: i0.Output, args: ["cellHover"] }], modeChange: [{ type: i0.Output, args: ["modeChange"] }] } });
|
|
3931
4236
|
|
|
3932
4237
|
function wireSignalFormsInputs(host, api) {
|
|
3933
4238
|
// Mirror Signal Forms flags onto the component. Effects run in the
|
|
@@ -3956,28 +4261,28 @@ class CalendarSingleDirective {
|
|
|
3956
4261
|
host = inject(CalendarComponent, { self: true });
|
|
3957
4262
|
/** Two-way value, forwarded to the hosting `CalendarComponent`. Signal Forms `Field` binds against this. */
|
|
3958
4263
|
value = this.host.value;
|
|
3959
|
-
/** Mirrors the bound field's disabled flag
|
|
4264
|
+
/** Mirrors the bound field's disabled flag; Signal Forms writes it, and the host calendar disables itself when it is `true`. Defaults to `false`. */
|
|
3960
4265
|
disabled = input(false, /* @ts-ignore */
|
|
3961
4266
|
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
3962
|
-
/** Mirrors the bound field's readonly flag
|
|
4267
|
+
/** Mirrors the bound field's readonly flag; the host calendar renders its grids read-only when it is `true`. Defaults to `false`. */
|
|
3963
4268
|
readonly = input(false, /* @ts-ignore */
|
|
3964
4269
|
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
3965
|
-
/** Mirrors the bound field's required flag. */
|
|
4270
|
+
/** Mirrors the bound field's required flag. Defaults to `false`. */
|
|
3966
4271
|
required = input(false, /* @ts-ignore */
|
|
3967
4272
|
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
3968
|
-
/** Mirrors the bound field's invalid flag. */
|
|
4273
|
+
/** Mirrors the bound field's invalid flag. Defaults to `false`. */
|
|
3969
4274
|
invalid = input(false, /* @ts-ignore */
|
|
3970
4275
|
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
3971
|
-
/** Mirrors the bound field's hidden flag. */
|
|
4276
|
+
/** Mirrors the bound field's hidden flag. Defaults to `false`. */
|
|
3972
4277
|
hidden = input(false, /* @ts-ignore */
|
|
3973
4278
|
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
3974
|
-
/** Mirrors the bound field's errors. */
|
|
4279
|
+
/** Mirrors the bound field's errors. Defaults to `[]` (no errors). */
|
|
3975
4280
|
errors = input([], /* @ts-ignore */
|
|
3976
4281
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
3977
|
-
/** Mirrors the bound field's disablement reasons. */
|
|
4282
|
+
/** Mirrors the bound field's disablement reasons. Defaults to `[]` (none). */
|
|
3978
4283
|
disabledReasons = input([], /* @ts-ignore */
|
|
3979
4284
|
...(ngDevMode ? [{ debugName: "disabledReasons" }] : /* istanbul ignore next */ []));
|
|
3980
|
-
/** Two-way `touched` flag — drives and reflects the field's touched state. */
|
|
4285
|
+
/** Two-way `touched` flag — drives and reflects the field's touched state, flipping to `true` when the calendar loses focus after an interaction. Defaults to `false`. */
|
|
3981
4286
|
touched = model(false, /* @ts-ignore */
|
|
3982
4287
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
3983
4288
|
constructor() {
|
|
@@ -4003,28 +4308,28 @@ class CalendarMultipleDirective {
|
|
|
4003
4308
|
host = inject(CalendarComponent, { self: true });
|
|
4004
4309
|
/** Two-way value, forwarded to the hosting `CalendarComponent`. Signal Forms `Field` binds against this. */
|
|
4005
4310
|
value = this.host.value;
|
|
4006
|
-
/** Mirrors the bound field's disabled flag
|
|
4311
|
+
/** Mirrors the bound field's disabled flag; Signal Forms writes it, and the host calendar disables itself when it is `true`. Defaults to `false`. */
|
|
4007
4312
|
disabled = input(false, /* @ts-ignore */
|
|
4008
4313
|
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
4009
|
-
/** Mirrors the bound field's readonly flag
|
|
4314
|
+
/** Mirrors the bound field's readonly flag; the host calendar renders its grids read-only when it is `true`. Defaults to `false`. */
|
|
4010
4315
|
readonly = input(false, /* @ts-ignore */
|
|
4011
4316
|
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
4012
|
-
/** Mirrors the bound field's required flag. */
|
|
4317
|
+
/** Mirrors the bound field's required flag. Defaults to `false`. */
|
|
4013
4318
|
required = input(false, /* @ts-ignore */
|
|
4014
4319
|
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
4015
|
-
/** Mirrors the bound field's invalid flag. */
|
|
4320
|
+
/** Mirrors the bound field's invalid flag. Defaults to `false`. */
|
|
4016
4321
|
invalid = input(false, /* @ts-ignore */
|
|
4017
4322
|
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
4018
|
-
/** Mirrors the bound field's hidden flag. */
|
|
4323
|
+
/** Mirrors the bound field's hidden flag. Defaults to `false`. */
|
|
4019
4324
|
hidden = input(false, /* @ts-ignore */
|
|
4020
4325
|
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
4021
|
-
/** Mirrors the bound field's errors. */
|
|
4326
|
+
/** Mirrors the bound field's errors. Defaults to `[]` (no errors). */
|
|
4022
4327
|
errors = input([], /* @ts-ignore */
|
|
4023
4328
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
4024
|
-
/** Mirrors the bound field's disablement reasons. */
|
|
4329
|
+
/** Mirrors the bound field's disablement reasons. Defaults to `[]` (none). */
|
|
4025
4330
|
disabledReasons = input([], /* @ts-ignore */
|
|
4026
4331
|
...(ngDevMode ? [{ debugName: "disabledReasons" }] : /* istanbul ignore next */ []));
|
|
4027
|
-
/** Two-way `touched` flag — drives and reflects the field's touched state. */
|
|
4332
|
+
/** Two-way `touched` flag — drives and reflects the field's touched state, flipping to `true` when the calendar loses focus after an interaction. Defaults to `false`. */
|
|
4028
4333
|
touched = model(false, /* @ts-ignore */
|
|
4029
4334
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
4030
4335
|
constructor() {
|
|
@@ -4050,28 +4355,28 @@ class CalendarRangeDirective {
|
|
|
4050
4355
|
host = inject(CalendarComponent, { self: true });
|
|
4051
4356
|
/** Two-way value, forwarded to the hosting `CalendarComponent`. Signal Forms `Field` binds against this. */
|
|
4052
4357
|
value = this.host.value;
|
|
4053
|
-
/** Mirrors the bound field's disabled flag
|
|
4358
|
+
/** Mirrors the bound field's disabled flag; Signal Forms writes it, and the host calendar disables itself when it is `true`. Defaults to `false`. */
|
|
4054
4359
|
disabled = input(false, /* @ts-ignore */
|
|
4055
4360
|
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
4056
|
-
/** Mirrors the bound field's readonly flag
|
|
4361
|
+
/** Mirrors the bound field's readonly flag; the host calendar renders its grids read-only when it is `true`. Defaults to `false`. */
|
|
4057
4362
|
readonly = input(false, /* @ts-ignore */
|
|
4058
4363
|
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
4059
|
-
/** Mirrors the bound field's required flag. */
|
|
4364
|
+
/** Mirrors the bound field's required flag. Defaults to `false`. */
|
|
4060
4365
|
required = input(false, /* @ts-ignore */
|
|
4061
4366
|
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
4062
|
-
/** Mirrors the bound field's invalid flag. */
|
|
4367
|
+
/** Mirrors the bound field's invalid flag. Defaults to `false`. */
|
|
4063
4368
|
invalid = input(false, /* @ts-ignore */
|
|
4064
4369
|
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
4065
|
-
/** Mirrors the bound field's hidden flag. */
|
|
4370
|
+
/** Mirrors the bound field's hidden flag. Defaults to `false`. */
|
|
4066
4371
|
hidden = input(false, /* @ts-ignore */
|
|
4067
4372
|
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
4068
|
-
/** Mirrors the bound field's errors. */
|
|
4373
|
+
/** Mirrors the bound field's errors. Defaults to `[]` (no errors). */
|
|
4069
4374
|
errors = input([], /* @ts-ignore */
|
|
4070
4375
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
4071
|
-
/** Mirrors the bound field's disablement reasons. */
|
|
4376
|
+
/** Mirrors the bound field's disablement reasons. Defaults to `[]` (none). */
|
|
4072
4377
|
disabledReasons = input([], /* @ts-ignore */
|
|
4073
4378
|
...(ngDevMode ? [{ debugName: "disabledReasons" }] : /* istanbul ignore next */ []));
|
|
4074
|
-
/** Two-way `touched` flag — drives and reflects the field's touched state. */
|
|
4379
|
+
/** Two-way `touched` flag — drives and reflects the field's touched state, flipping to `true` when the calendar loses focus after an interaction. Defaults to `false`. */
|
|
4075
4380
|
touched = model(false, /* @ts-ignore */
|
|
4076
4381
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
4077
4382
|
constructor() {
|
|
@@ -4632,14 +4937,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
4632
4937
|
function provideNativeDateAdapter() {
|
|
4633
4938
|
return makeEnvironmentProviders([
|
|
4634
4939
|
NativeDateAdapter,
|
|
4635
|
-
{ provide:
|
|
4940
|
+
{ provide: TW_DATE_ADAPTER, useExisting: NativeDateAdapter },
|
|
4636
4941
|
]);
|
|
4637
4942
|
}
|
|
4638
4943
|
/** Provides a custom `DateAdapter` implementation. */
|
|
4639
4944
|
function provideTwCalendar(config) {
|
|
4640
4945
|
return makeEnvironmentProviders([
|
|
4641
4946
|
config.adapter,
|
|
4642
|
-
{ provide:
|
|
4947
|
+
{ provide: TW_DATE_ADAPTER, useExisting: config.adapter },
|
|
4643
4948
|
...(config.extraProviders ?? []),
|
|
4644
4949
|
]);
|
|
4645
4950
|
}
|
|
@@ -4678,5 +4983,5 @@ function toTwDateRange(value) {
|
|
|
4678
4983
|
* Generated bundle index. Do not edit.
|
|
4679
4984
|
*/
|
|
4680
4985
|
|
|
4681
|
-
export { CALENDAR_SELECTION_STRATEGY, CalendarCellComponent, CalendarComponent, CalendarHeaderComponent, CalendarIntl, CalendarMultipleDirective, CalendarPresetsDirective, CalendarRangeDirective, CalendarSelectionStrategy, CalendarSingleDirective, CalendarViewBase, DATE_ADAPTER, DATE_FORMATS, DATE_SERIALIZATION, DAYS_PER_WEEK, DateAdapter, MONTHS_PER_ROW, MonthViewComponent, MultiSelectionStrategy, NativeDateAdapter, RangeSelectionStrategy, SingleSelectionStrategy, TZ_OVERRIDE, TwDateRange, WEEKS_PER_MONTH, WeekSelectionStrategy, YEARS_PER_PAGE, YEARS_PER_ROW, YearViewComponent, YearsViewComponent, calendarRequiredValidator, calendarValidator, createCalendarCell, createDateRange, createGrid, de, emptyCalendarValue, es, fr, getFirstDayOfMonth, getMultiYearStartingYear, getWeekdayHeaders, isCalendarValueEmpty, isDateDisabled, isDateInRange, isMonthDisabled, isYearDisabled, ja, navigateGrid, provideCalendarIntl, provideCalendarSelectionStrategy, provideMultiSelectionStrategy, provideNativeDateAdapter, provideRangeSelectionStrategy, provideSingleSelectionStrategy, provideTwCalendar, provideWeekSelectionStrategy, pt, serializeCalendarValue, toTwDateRange, yearsPerPage };
|
|
4986
|
+
export { CALENDAR_SELECTION_STRATEGY, CalendarCellComponent, CalendarComponent, CalendarHeaderComponent, CalendarIntl, CalendarMultipleDirective, CalendarPresetsDirective, CalendarRangeDirective, CalendarSelectionStrategy, CalendarSingleDirective, CalendarViewBase, DATE_ADAPTER, DATE_FORMATS, DATE_SERIALIZATION, DAYS_PER_WEEK, DateAdapter, MONTHS_PER_ROW, MonthViewComponent, MultiSelectionStrategy, NativeDateAdapter, RangeSelectionStrategy, SingleSelectionStrategy, TW_CALENDAR_SELECTION_STRATEGY, TW_DATE_ADAPTER, TW_DATE_FORMATS, TW_DATE_SERIALIZATION, TW_TZ_OVERRIDE, TZ_OVERRIDE, TwDateRange, WEEKS_PER_MONTH, WeekSelectionStrategy, YEARS_PER_PAGE, YEARS_PER_ROW, YearViewComponent, YearsViewComponent, calendarRequiredValidator, calendarValidator, createCalendarCell, createDateRange, createGrid, de, emptyCalendarValue, es, fr, getFirstDayOfMonth, getMultiYearStartingYear, getWeekdayHeaders, isCalendarValueEmpty, isDateDisabled, isDateInRange, isMonthDisabled, isYearDisabled, ja, navigateGrid, provideCalendarIntl, provideCalendarSelectionStrategy, provideMultiSelectionStrategy, provideNativeDateAdapter, provideRangeSelectionStrategy, provideSingleSelectionStrategy, provideTwCalendar, provideWeekSelectionStrategy, pt, serializeCalendarValue, toTwDateRange, yearsPerPage };
|
|
4682
4987
|
//# sourceMappingURL=cdevhub-ngx-tw-calendar.mjs.map
|