ngx-com 0.0.18 → 0.0.19

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.
@@ -242,6 +242,33 @@ class NativeDateAdapter extends DateAdapter {
242
242
  return dateDiff > 0 ? 1 : -1;
243
243
  return 0;
244
244
  }
245
+ getHours(date) {
246
+ return date.getHours();
247
+ }
248
+ getMinutes(date) {
249
+ return date.getMinutes();
250
+ }
251
+ getSeconds(date) {
252
+ return date.getSeconds();
253
+ }
254
+ setTime(date, hours, minutes, seconds) {
255
+ const result = new Date(date);
256
+ result.setHours(hours, minutes, seconds, 0);
257
+ return result;
258
+ }
259
+ createDateTime(year, month, day, hours, minutes, seconds) {
260
+ if (month < 0 || month > 11) {
261
+ throw new Error(`Invalid month index "${month}". Month index must be between 0 and 11.`);
262
+ }
263
+ if (day < 1) {
264
+ throw new Error(`Invalid date "${day}". Date must be greater than 0.`);
265
+ }
266
+ const result = new Date(year, month, day, hours, minutes, seconds);
267
+ if (result.getMonth() !== month) {
268
+ throw new Error(`Invalid date "${day}" for month index "${month}".`);
269
+ }
270
+ return result;
271
+ }
245
272
  clampDate(date, min, max) {
246
273
  if (min && this.compareDate(date, min) < 0) {
247
274
  return min;
@@ -278,6 +305,11 @@ class NativeDateAdapter extends DateAdapter {
278
305
  monthYearShort: { year: 'numeric', month: 'short' },
279
306
  dayMonth: { day: 'numeric', month: 'long' },
280
307
  dayMonthYear: { day: 'numeric', month: 'long', year: 'numeric' },
308
+ time: { hour: 'numeric', minute: '2-digit' },
309
+ timeWithSeconds: { hour: 'numeric', minute: '2-digit', second: '2-digit' },
310
+ dateTimeShort: { dateStyle: 'short', timeStyle: 'short' },
311
+ dateTimeMedium: { dateStyle: 'medium', timeStyle: 'short' },
312
+ dateTimeLong: { dateStyle: 'long', timeStyle: 'medium' },
281
313
  };
282
314
  return formatMap[format] ?? { dateStyle: 'medium' };
283
315
  }
@@ -3371,6 +3403,945 @@ const datepickerRangeSeparatorVariants = cva([
3371
3403
  },
3372
3404
  });
3373
3405
 
3406
+ /**
3407
+ * CVA variants for the time picker container.
3408
+ *
3409
+ * @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
3410
+ * `--color-ring`, `--color-warn`, `--color-success`, `--radius-input`
3411
+ */
3412
+ const timepickerContainerVariants = cva([
3413
+ 'inline-flex',
3414
+ 'items-center',
3415
+ 'gap-1',
3416
+ 'rounded-input',
3417
+ 'transition-colors',
3418
+ 'duration-150',
3419
+ ], {
3420
+ variants: {
3421
+ variant: {
3422
+ standalone: [
3423
+ 'border',
3424
+ 'border-input-border',
3425
+ 'bg-input-background',
3426
+ 'text-input-foreground',
3427
+ 'ring-offset-background',
3428
+ 'focus-within:outline-none',
3429
+ 'focus-within:ring-2',
3430
+ 'focus-within:ring-offset-2',
3431
+ 'focus-within:ring-ring',
3432
+ ],
3433
+ embedded: [
3434
+ 'border-transparent',
3435
+ 'bg-transparent',
3436
+ 'text-foreground',
3437
+ ],
3438
+ },
3439
+ size: {
3440
+ sm: ['h-8', 'px-2', 'text-xs', 'gap-0.5'],
3441
+ default: ['h-10', 'px-3', 'text-sm', 'gap-1'],
3442
+ lg: ['h-12', 'px-4', 'text-base', 'gap-1.5'],
3443
+ },
3444
+ state: {
3445
+ default: [],
3446
+ error: [
3447
+ 'border-warn',
3448
+ 'focus-within:ring-warn',
3449
+ ],
3450
+ success: [
3451
+ 'border-success',
3452
+ 'focus-within:ring-success',
3453
+ ],
3454
+ },
3455
+ },
3456
+ compoundVariants: [
3457
+ {
3458
+ variant: 'embedded',
3459
+ state: 'error',
3460
+ class: [],
3461
+ },
3462
+ {
3463
+ variant: 'embedded',
3464
+ state: 'success',
3465
+ class: [],
3466
+ },
3467
+ ],
3468
+ defaultVariants: {
3469
+ variant: 'standalone',
3470
+ size: 'default',
3471
+ state: 'default',
3472
+ },
3473
+ });
3474
+ /**
3475
+ * CVA variants for the disabled state of time picker.
3476
+ *
3477
+ * @tokens `--color-disabled`, `--color-disabled-foreground`
3478
+ */
3479
+ const timepickerDisabledVariants = cva([
3480
+ 'cursor-not-allowed',
3481
+ 'bg-disabled',
3482
+ 'text-disabled-foreground',
3483
+ 'pointer-events-none',
3484
+ ]);
3485
+ /**
3486
+ * CVA variants for each time segment input.
3487
+ *
3488
+ * @tokens `--color-primary-subtle`, `--color-primary-subtle-foreground`, `--radius-interactive-sm`
3489
+ */
3490
+ const timepickerSegmentVariants = cva([
3491
+ 'bg-transparent',
3492
+ 'outline-none',
3493
+ 'text-center',
3494
+ 'font-mono',
3495
+ 'tabular-nums',
3496
+ 'select-all',
3497
+ 'focus:bg-primary-subtle',
3498
+ 'focus:text-primary-subtle-foreground',
3499
+ 'focus:rounded-interactive-sm',
3500
+ ], {
3501
+ variants: {
3502
+ size: {
3503
+ sm: ['w-5', 'text-xs'],
3504
+ default: ['w-7', 'text-sm'],
3505
+ lg: ['w-9', 'text-base'],
3506
+ },
3507
+ },
3508
+ defaultVariants: {
3509
+ size: 'default',
3510
+ },
3511
+ });
3512
+ /**
3513
+ * CVA variants for the colon separator.
3514
+ *
3515
+ * @tokens `--color-muted-foreground`
3516
+ */
3517
+ const timepickerSeparatorVariants = cva([
3518
+ 'text-muted-foreground',
3519
+ 'select-none',
3520
+ 'font-mono',
3521
+ ], {
3522
+ variants: {
3523
+ size: {
3524
+ sm: ['text-xs'],
3525
+ default: ['text-sm'],
3526
+ lg: ['text-base'],
3527
+ },
3528
+ },
3529
+ defaultVariants: {
3530
+ size: 'default',
3531
+ },
3532
+ });
3533
+ /**
3534
+ * CVA variants for the AM/PM toggle button.
3535
+ *
3536
+ * @tokens `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`, `--color-ring`,
3537
+ * `--radius-control-sm`
3538
+ */
3539
+ const timepickerPeriodVariants = cva([
3540
+ 'inline-flex',
3541
+ 'items-center',
3542
+ 'justify-center',
3543
+ 'rounded-control-sm',
3544
+ 'font-medium',
3545
+ 'transition-colors',
3546
+ 'select-none',
3547
+ 'bg-muted',
3548
+ 'text-muted-foreground',
3549
+ 'hover:bg-muted-hover',
3550
+ 'focus:outline-none',
3551
+ 'focus:ring-1',
3552
+ 'focus:ring-ring',
3553
+ ], {
3554
+ variants: {
3555
+ size: {
3556
+ sm: ['h-5', 'px-1', 'text-xs', 'ml-0.5'],
3557
+ default: ['h-6', 'px-1.5', 'text-xs', 'ml-1'],
3558
+ lg: ['h-7', 'px-2', 'text-sm', 'ml-1.5'],
3559
+ },
3560
+ },
3561
+ defaultVariants: {
3562
+ size: 'default',
3563
+ },
3564
+ });
3565
+ /**
3566
+ * CVA variants for the time section divider in datepicker panel.
3567
+ *
3568
+ * @tokens `--color-border-subtle`
3569
+ */
3570
+ const timepickerSectionVariants = cva([
3571
+ 'flex',
3572
+ 'items-center',
3573
+ 'justify-center',
3574
+ 'border-t',
3575
+ 'border-border-subtle',
3576
+ ], {
3577
+ variants: {
3578
+ size: {
3579
+ sm: ['pt-2', 'mt-2'],
3580
+ default: ['pt-3', 'mt-3'],
3581
+ lg: ['pt-4', 'mt-4'],
3582
+ },
3583
+ },
3584
+ defaultVariants: {
3585
+ size: 'default',
3586
+ },
3587
+ });
3588
+ /**
3589
+ * CVA variants for time labels in date range picker.
3590
+ *
3591
+ * @tokens `--color-muted-foreground`
3592
+ */
3593
+ const timepickerLabelVariants = cva([
3594
+ 'text-muted-foreground',
3595
+ 'font-medium',
3596
+ ], {
3597
+ variants: {
3598
+ size: {
3599
+ sm: ['text-xs'],
3600
+ default: ['text-xs'],
3601
+ lg: ['text-sm'],
3602
+ },
3603
+ },
3604
+ defaultVariants: {
3605
+ size: 'default',
3606
+ },
3607
+ });
3608
+
3609
+ /**
3610
+ * Types and interfaces for the TimePicker component.
3611
+ */
3612
+ /** Creates a ComTimeValue */
3613
+ function createTimeValue(hours = 0, minutes = 0, seconds = 0) {
3614
+ return { hours, minutes, seconds };
3615
+ }
3616
+ /**
3617
+ * Compares two ComTimeValue objects.
3618
+ * @returns negative if a < b, 0 if equal, positive if a > b
3619
+ */
3620
+ function compareTime(a, b) {
3621
+ const diff = a.hours * 3600 + a.minutes * 60 + a.seconds - (b.hours * 3600 + b.minutes * 60 + b.seconds);
3622
+ return diff;
3623
+ }
3624
+ /** Generates a unique ID for time picker instances */
3625
+ let timePickerIdCounter = 0;
3626
+ function generateTimePickerId() {
3627
+ return `com-time-picker-${timePickerIdCounter++}`;
3628
+ }
3629
+
3630
+ /**
3631
+ * Time picker component with segmented numeric input fields.
3632
+ * Supports standalone usage with ControlValueAccessor and embedded usage
3633
+ * within datepicker/date-range-picker panels.
3634
+ *
3635
+ * Visual layout: `[HH] : [MM] : [SS] [AM|PM]`
3636
+ *
3637
+ * @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
3638
+ * `--color-ring`, `--color-primary-subtle`, `--color-primary-subtle-foreground`,
3639
+ * `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`,
3640
+ * `--color-disabled`, `--color-disabled-foreground`,
3641
+ * `--color-warn`, `--color-success`, `--color-border`
3642
+ *
3643
+ * @example
3644
+ * ```html
3645
+ * <!-- Standalone with reactive forms -->
3646
+ * <com-time-picker formControlName="startTime" />
3647
+ *
3648
+ * <!-- 12-hour format with seconds -->
3649
+ * <com-time-picker formControlName="alarm" [use12HourFormat]="true" [showSeconds]="true" />
3650
+ *
3651
+ * <!-- 15-minute steps -->
3652
+ * <com-time-picker formControlName="meeting" [minuteStep]="15" />
3653
+ *
3654
+ * <!-- Embedded inside datepicker panel -->
3655
+ * <com-time-picker variant="embedded" [value]="time" (timeChange)="onTime($event)" />
3656
+ * ```
3657
+ */
3658
+ class ComTimePicker {
3659
+ localeId = inject(LOCALE_ID);
3660
+ ngControl = inject(NgControl, { optional: true, self: true });
3661
+ timepickerId = generateTimePickerId();
3662
+ hoursInputRef = viewChild('hoursInput', ...(ngDevMode ? [{ debugName: "hoursInputRef" }] : []));
3663
+ minutesInputRef = viewChild('minutesInput', ...(ngDevMode ? [{ debugName: "minutesInputRef" }] : []));
3664
+ secondsInputRef = viewChild('secondsInput', ...(ngDevMode ? [{ debugName: "secondsInputRef" }] : []));
3665
+ periodButtonRef = viewChild('periodButton', ...(ngDevMode ? [{ debugName: "periodButtonRef" }] : []));
3666
+ // ============ INPUTS ============
3667
+ /** Current time value. */
3668
+ value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
3669
+ /** Whether the time picker is disabled. */
3670
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3671
+ /** Whether the time picker is required. */
3672
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
3673
+ /** Whether to show the seconds segment. */
3674
+ showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
3675
+ /** 12h vs 24h format. `null` = auto-detect from locale. */
3676
+ use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
3677
+ /** Step interval for minutes. */
3678
+ minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
3679
+ /** Step interval for seconds. */
3680
+ secondStep = input(1, ...(ngDevMode ? [{ debugName: "secondStep" }] : []));
3681
+ /** Minimum selectable time. */
3682
+ minTime = input(null, ...(ngDevMode ? [{ debugName: "minTime" }] : []));
3683
+ /** Maximum selectable time. */
3684
+ maxTime = input(null, ...(ngDevMode ? [{ debugName: "maxTime" }] : []));
3685
+ /** Visual variant. */
3686
+ variant = input('standalone', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3687
+ /** Size variant. */
3688
+ size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
3689
+ /** Validation state. */
3690
+ state = input('default', ...(ngDevMode ? [{ debugName: "state" }] : []));
3691
+ /** Accessible label for the group. */
3692
+ ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
3693
+ /** Additional CSS classes. */
3694
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : {}), alias: 'class' });
3695
+ /** Placeholder text for empty segments. */
3696
+ placeholder = input('--', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
3697
+ // ============ OUTPUTS ============
3698
+ /** Emitted when time value changes. */
3699
+ timeChange = output();
3700
+ // ============ INTERNAL STATE ============
3701
+ /** Internal value state. */
3702
+ internalValue = linkedSignal(() => this.value() ?? null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
3703
+ /** Which segment is currently focused. */
3704
+ activeSegment = signal(null, ...(ngDevMode ? [{ debugName: "activeSegment" }] : []));
3705
+ /** Pending typed digits for auto-advance. */
3706
+ pendingDigits = signal('', ...(ngDevMode ? [{ debugName: "pendingDigits" }] : []));
3707
+ /** Live announcements for screen readers. */
3708
+ liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "liveAnnouncement" }] : []));
3709
+ // ============ COMPUTED STATE ============
3710
+ /** Whether to use 12-hour format. */
3711
+ is12Hour = computed(() => {
3712
+ const explicit = this.use12HourFormat();
3713
+ if (explicit !== null)
3714
+ return explicit;
3715
+ try {
3716
+ const options = new Intl.DateTimeFormat(this.localeId, { hour: 'numeric' }).resolvedOptions();
3717
+ return options.hour12 === true;
3718
+ }
3719
+ catch {
3720
+ return false;
3721
+ }
3722
+ }, ...(ngDevMode ? [{ debugName: "is12Hour" }] : []));
3723
+ /** Current period (AM/PM). */
3724
+ period = computed(() => {
3725
+ const value = this.internalValue();
3726
+ if (!value)
3727
+ return 'AM';
3728
+ return value.hours >= 12 ? 'PM' : 'AM';
3729
+ }, ...(ngDevMode ? [{ debugName: "period" }] : []));
3730
+ /** Display hours (converted from 24h to 12h when needed). */
3731
+ displayHours = computed(() => {
3732
+ const value = this.internalValue();
3733
+ if (!value)
3734
+ return null;
3735
+ if (!this.is12Hour())
3736
+ return value.hours;
3737
+ const h = value.hours % 12;
3738
+ return h === 0 ? 12 : h;
3739
+ }, ...(ngDevMode ? [{ debugName: "displayHours" }] : []));
3740
+ /** Formatted hours string. */
3741
+ formattedHours = computed(() => {
3742
+ const h = this.displayHours();
3743
+ if (h === null)
3744
+ return '';
3745
+ return h.toString().padStart(2, '0');
3746
+ }, ...(ngDevMode ? [{ debugName: "formattedHours" }] : []));
3747
+ /** Formatted minutes string. */
3748
+ formattedMinutes = computed(() => {
3749
+ const value = this.internalValue();
3750
+ if (!value)
3751
+ return '';
3752
+ return value.minutes.toString().padStart(2, '0');
3753
+ }, ...(ngDevMode ? [{ debugName: "formattedMinutes" }] : []));
3754
+ /** Formatted seconds string. */
3755
+ formattedSeconds = computed(() => {
3756
+ const value = this.internalValue();
3757
+ if (!value)
3758
+ return '';
3759
+ return value.seconds.toString().padStart(2, '0');
3760
+ }, ...(ngDevMode ? [{ debugName: "formattedSeconds" }] : []));
3761
+ /** Container classes. */
3762
+ containerClasses = computed(() => {
3763
+ const base = timepickerContainerVariants({
3764
+ variant: this.variant(),
3765
+ size: this.size(),
3766
+ state: this.state(),
3767
+ });
3768
+ const disabled = this.disabled() ? timepickerDisabledVariants() : '';
3769
+ return joinClasses(base, disabled, this.userClass());
3770
+ }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
3771
+ /** Segment input classes. */
3772
+ segmentClasses = computed(() => {
3773
+ return timepickerSegmentVariants({ size: this.size() });
3774
+ }, ...(ngDevMode ? [{ debugName: "segmentClasses" }] : []));
3775
+ /** Separator classes. */
3776
+ separatorClasses = computed(() => {
3777
+ return timepickerSeparatorVariants({ size: this.size() });
3778
+ }, ...(ngDevMode ? [{ debugName: "separatorClasses" }] : []));
3779
+ /** Period button classes. */
3780
+ periodClasses = computed(() => {
3781
+ return timepickerPeriodVariants({ size: this.size() });
3782
+ }, ...(ngDevMode ? [{ debugName: "periodClasses" }] : []));
3783
+ // ============ CVA CALLBACKS ============
3784
+ onChange = () => { };
3785
+ onTouched = () => { };
3786
+ onValidatorChange = () => { };
3787
+ constructor() {
3788
+ if (this.ngControl) {
3789
+ this.ngControl.valueAccessor = this;
3790
+ }
3791
+ }
3792
+ // ============ CVA IMPLEMENTATION ============
3793
+ writeValue(value) {
3794
+ this.internalValue.set(value);
3795
+ }
3796
+ registerOnChange(fn) {
3797
+ this.onChange = fn;
3798
+ }
3799
+ registerOnTouched(fn) {
3800
+ this.onTouched = fn;
3801
+ }
3802
+ setDisabledState(_isDisabled) {
3803
+ // Disabled state is handled via the disabled input
3804
+ }
3805
+ // ============ VALIDATOR IMPLEMENTATION ============
3806
+ validate() {
3807
+ const value = this.internalValue();
3808
+ if (this.required() && !value) {
3809
+ return { required: true };
3810
+ }
3811
+ if (value) {
3812
+ const minTime = this.minTime();
3813
+ if (minTime && compareTime(value, minTime) < 0) {
3814
+ return { minTime: { min: minTime, actual: value } };
3815
+ }
3816
+ const maxTime = this.maxTime();
3817
+ if (maxTime && compareTime(value, maxTime) > 0) {
3818
+ return { maxTime: { max: maxTime, actual: value } };
3819
+ }
3820
+ }
3821
+ return null;
3822
+ }
3823
+ registerOnValidatorChange(fn) {
3824
+ this.onValidatorChange = fn;
3825
+ }
3826
+ // ============ EVENT HANDLERS ============
3827
+ onSegmentFocus(segment) {
3828
+ this.activeSegment.set(segment);
3829
+ this.pendingDigits.set('');
3830
+ }
3831
+ onSegmentBlur(segment) {
3832
+ this.activeSegment.set(null);
3833
+ this.pendingDigits.set('');
3834
+ this.snapToStep(segment);
3835
+ this.onTouched();
3836
+ }
3837
+ onSegmentInput(event, segment) {
3838
+ // Prevent default browser input handling — we manage value via keydown
3839
+ const input = event.target;
3840
+ const value = this.internalValue();
3841
+ // Restore the formatted value to prevent browser from changing display
3842
+ if (segment === 'hours') {
3843
+ input.value = this.formattedHours();
3844
+ }
3845
+ else if (segment === 'minutes') {
3846
+ input.value = this.formattedMinutes();
3847
+ }
3848
+ else {
3849
+ input.value = this.formattedSeconds();
3850
+ }
3851
+ }
3852
+ onSegmentKeydown(event, segment) {
3853
+ switch (event.key) {
3854
+ case 'ArrowUp':
3855
+ event.preventDefault();
3856
+ this.incrementSegment(segment, 1);
3857
+ break;
3858
+ case 'ArrowDown':
3859
+ event.preventDefault();
3860
+ this.incrementSegment(segment, -1);
3861
+ break;
3862
+ case 'ArrowRight':
3863
+ event.preventDefault();
3864
+ this.focusNextSegment(segment);
3865
+ break;
3866
+ case 'ArrowLeft':
3867
+ event.preventDefault();
3868
+ this.focusPrevSegment(segment);
3869
+ break;
3870
+ case 'Home':
3871
+ event.preventDefault();
3872
+ this.setSegmentToMin(segment);
3873
+ break;
3874
+ case 'End':
3875
+ event.preventDefault();
3876
+ this.setSegmentToMax(segment);
3877
+ break;
3878
+ case 'Backspace':
3879
+ case 'Delete':
3880
+ event.preventDefault();
3881
+ this.pendingDigits.set('');
3882
+ break;
3883
+ default:
3884
+ if (/^[0-9]$/.test(event.key)) {
3885
+ event.preventDefault();
3886
+ this.handleDigitInput(event.key, segment);
3887
+ }
3888
+ break;
3889
+ }
3890
+ }
3891
+ onPeriodKeydown(event) {
3892
+ switch (event.key) {
3893
+ case 'ArrowUp':
3894
+ case 'ArrowDown':
3895
+ event.preventDefault();
3896
+ this.togglePeriod();
3897
+ break;
3898
+ case 'ArrowLeft':
3899
+ event.preventDefault();
3900
+ this.focusPrevSegment('period');
3901
+ break;
3902
+ case 'a':
3903
+ case 'A':
3904
+ event.preventDefault();
3905
+ this.setPeriod('AM');
3906
+ break;
3907
+ case 'p':
3908
+ case 'P':
3909
+ event.preventDefault();
3910
+ this.setPeriod('PM');
3911
+ break;
3912
+ }
3913
+ }
3914
+ togglePeriod() {
3915
+ const value = this.internalValue();
3916
+ if (!value) {
3917
+ this.updateValue({ hours: 12, minutes: 0, seconds: 0 });
3918
+ return;
3919
+ }
3920
+ const newHours = value.hours >= 12 ? value.hours - 12 : value.hours + 12;
3921
+ this.updateValue({ ...value, hours: newHours });
3922
+ }
3923
+ // ============ PRIVATE METHODS ============
3924
+ setPeriod(period) {
3925
+ const value = this.internalValue();
3926
+ if (!value) {
3927
+ const hours = period === 'AM' ? 0 : 12;
3928
+ this.updateValue({ hours, minutes: 0, seconds: 0 });
3929
+ return;
3930
+ }
3931
+ const currentPeriod = this.period();
3932
+ if (currentPeriod === period)
3933
+ return;
3934
+ const newHours = period === 'AM' ? value.hours - 12 : value.hours + 12;
3935
+ this.updateValue({ ...value, hours: newHours });
3936
+ }
3937
+ incrementSegment(segment, direction) {
3938
+ const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
3939
+ const step = segment === 'minutes' ? this.minuteStep() : segment === 'seconds' ? this.secondStep() : 1;
3940
+ const delta = step * direction;
3941
+ let newValue;
3942
+ switch (segment) {
3943
+ case 'hours': {
3944
+ const max = this.is12Hour() ? 12 : 23;
3945
+ const min = this.is12Hour() ? 1 : 0;
3946
+ let h = this.is12Hour() ? (this.displayHours() ?? min) : value.hours;
3947
+ h += delta;
3948
+ // Wrap
3949
+ if (this.is12Hour()) {
3950
+ if (h > max)
3951
+ h = min;
3952
+ if (h < min)
3953
+ h = max;
3954
+ // Convert back to 24h
3955
+ const isPM = this.period() === 'PM';
3956
+ let h24 = h === 12 ? 0 : h;
3957
+ if (isPM)
3958
+ h24 += 12;
3959
+ newValue = { ...value, hours: h24 };
3960
+ }
3961
+ else {
3962
+ if (h > 23)
3963
+ h = 0;
3964
+ if (h < 0)
3965
+ h = 23;
3966
+ newValue = { ...value, hours: h };
3967
+ }
3968
+ break;
3969
+ }
3970
+ case 'minutes': {
3971
+ let m = value.minutes + delta;
3972
+ if (m > 59)
3973
+ m = 0;
3974
+ if (m < 0)
3975
+ m = 59;
3976
+ newValue = { ...value, minutes: m };
3977
+ break;
3978
+ }
3979
+ case 'seconds': {
3980
+ let s = value.seconds + delta;
3981
+ if (s > 59)
3982
+ s = 0;
3983
+ if (s < 0)
3984
+ s = 59;
3985
+ newValue = { ...value, seconds: s };
3986
+ break;
3987
+ }
3988
+ }
3989
+ this.updateValue(newValue);
3990
+ }
3991
+ handleDigitInput(digit, segment) {
3992
+ const pending = this.pendingDigits() + digit;
3993
+ const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
3994
+ let parsed = parseInt(pending, 10);
3995
+ switch (segment) {
3996
+ case 'hours': {
3997
+ const max = this.is12Hour() ? 12 : 23;
3998
+ const min = this.is12Hour() ? 1 : 0;
3999
+ if (parsed > max)
4000
+ parsed = parseInt(digit, 10);
4001
+ if (parsed < min && pending.length >= 2)
4002
+ parsed = min;
4003
+ // Convert to 24h if 12h mode
4004
+ let h24 = parsed;
4005
+ if (this.is12Hour()) {
4006
+ const isPM = this.period() === 'PM';
4007
+ h24 = parsed === 12 ? 0 : parsed;
4008
+ if (isPM)
4009
+ h24 += 12;
4010
+ }
4011
+ this.updateValue({ ...value, hours: h24 });
4012
+ break;
4013
+ }
4014
+ case 'minutes': {
4015
+ if (parsed > 59)
4016
+ parsed = parseInt(digit, 10);
4017
+ this.updateValue({ ...value, minutes: parsed });
4018
+ break;
4019
+ }
4020
+ case 'seconds': {
4021
+ if (parsed > 59)
4022
+ parsed = parseInt(digit, 10);
4023
+ this.updateValue({ ...value, seconds: parsed });
4024
+ break;
4025
+ }
4026
+ }
4027
+ // Auto-advance after 2 digits
4028
+ if (pending.length >= 2) {
4029
+ this.pendingDigits.set('');
4030
+ this.focusNextSegment(segment);
4031
+ }
4032
+ else {
4033
+ this.pendingDigits.set(pending);
4034
+ }
4035
+ }
4036
+ snapToStep(segment) {
4037
+ const value = this.internalValue();
4038
+ if (!value)
4039
+ return;
4040
+ if (segment === 'minutes' && this.minuteStep() > 1) {
4041
+ const step = this.minuteStep();
4042
+ const snapped = Math.round(value.minutes / step) * step;
4043
+ const clamped = Math.min(snapped, 59);
4044
+ if (clamped !== value.minutes) {
4045
+ this.updateValue({ ...value, minutes: clamped });
4046
+ }
4047
+ }
4048
+ if (segment === 'seconds' && this.secondStep() > 1) {
4049
+ const step = this.secondStep();
4050
+ const snapped = Math.round(value.seconds / step) * step;
4051
+ const clamped = Math.min(snapped, 59);
4052
+ if (clamped !== value.seconds) {
4053
+ this.updateValue({ ...value, seconds: clamped });
4054
+ }
4055
+ }
4056
+ }
4057
+ setSegmentToMin(segment) {
4058
+ const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
4059
+ switch (segment) {
4060
+ case 'hours': {
4061
+ if (this.is12Hour()) {
4062
+ // Min display is 1; convert to 24h
4063
+ const isPM = this.period() === 'PM';
4064
+ const h24 = isPM ? 13 : 1;
4065
+ this.updateValue({ ...value, hours: h24 });
4066
+ }
4067
+ else {
4068
+ this.updateValue({ ...value, hours: 0 });
4069
+ }
4070
+ break;
4071
+ }
4072
+ case 'minutes':
4073
+ this.updateValue({ ...value, minutes: 0 });
4074
+ break;
4075
+ case 'seconds':
4076
+ this.updateValue({ ...value, seconds: 0 });
4077
+ break;
4078
+ }
4079
+ }
4080
+ setSegmentToMax(segment) {
4081
+ const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
4082
+ switch (segment) {
4083
+ case 'hours': {
4084
+ if (this.is12Hour()) {
4085
+ // Max display is 12; 12 in 12h = 0 in 24h (for AM) or 12 (for PM)
4086
+ const isPM = this.period() === 'PM';
4087
+ const h24 = isPM ? 12 : 0;
4088
+ this.updateValue({ ...value, hours: h24 });
4089
+ }
4090
+ else {
4091
+ this.updateValue({ ...value, hours: 23 });
4092
+ }
4093
+ break;
4094
+ }
4095
+ case 'minutes':
4096
+ this.updateValue({ ...value, minutes: 59 });
4097
+ break;
4098
+ case 'seconds':
4099
+ this.updateValue({ ...value, seconds: 59 });
4100
+ break;
4101
+ }
4102
+ }
4103
+ focusNextSegment(current) {
4104
+ switch (current) {
4105
+ case 'hours':
4106
+ this.minutesInputRef()?.nativeElement.focus();
4107
+ break;
4108
+ case 'minutes':
4109
+ if (this.showSeconds()) {
4110
+ this.secondsInputRef()?.nativeElement.focus();
4111
+ }
4112
+ else if (this.is12Hour()) {
4113
+ this.periodButtonRef()?.nativeElement.focus();
4114
+ }
4115
+ break;
4116
+ case 'seconds':
4117
+ if (this.is12Hour()) {
4118
+ this.periodButtonRef()?.nativeElement.focus();
4119
+ }
4120
+ break;
4121
+ }
4122
+ }
4123
+ focusPrevSegment(current) {
4124
+ switch (current) {
4125
+ case 'minutes':
4126
+ this.hoursInputRef()?.nativeElement.focus();
4127
+ break;
4128
+ case 'seconds':
4129
+ this.minutesInputRef()?.nativeElement.focus();
4130
+ break;
4131
+ case 'period':
4132
+ if (this.showSeconds()) {
4133
+ this.secondsInputRef()?.nativeElement.focus();
4134
+ }
4135
+ else {
4136
+ this.minutesInputRef()?.nativeElement.focus();
4137
+ }
4138
+ break;
4139
+ }
4140
+ }
4141
+ updateValue(value) {
4142
+ this.internalValue.set(value);
4143
+ this.onChange(value);
4144
+ this.timeChange.emit(value);
4145
+ this.onValidatorChange();
4146
+ if (value) {
4147
+ const h = this.is12Hour()
4148
+ ? `${(value.hours % 12 || 12)}:${value.minutes.toString().padStart(2, '0')}${this.showSeconds() ? ':' + value.seconds.toString().padStart(2, '0') : ''} ${value.hours >= 12 ? 'PM' : 'AM'}`
4149
+ : `${value.hours.toString().padStart(2, '0')}:${value.minutes.toString().padStart(2, '0')}${this.showSeconds() ? ':' + value.seconds.toString().padStart(2, '0') : ''}`;
4150
+ this.liveAnnouncement.set(`Time set to ${h}`);
4151
+ }
4152
+ }
4153
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComTimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
4154
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComTimePicker, isStandalone: true, selector: "com-time-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, secondStep: { classPropertyName: "secondStep", publicName: "secondStep", isSignal: true, isRequired: false, transformFunction: null }, minTime: { classPropertyName: "minTime", publicName: "minTime", isSignal: true, isRequired: false, transformFunction: null }, maxTime: { classPropertyName: "maxTime", publicName: "maxTime", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timeChange: "timeChange" }, host: { properties: { "class.com-time-picker-disabled": "disabled()", "attr.role": "\"group\"", "attr.aria-label": "ariaLabel() || \"Time picker\"", "attr.aria-disabled": "disabled() || null" }, classAttribute: "com-time-picker-host inline-block" }, viewQueries: [{ propertyName: "hoursInputRef", first: true, predicate: ["hoursInput"], descendants: true, isSignal: true }, { propertyName: "minutesInputRef", first: true, predicate: ["minutesInput"], descendants: true, isSignal: true }, { propertyName: "secondsInputRef", first: true, predicate: ["secondsInput"], descendants: true, isSignal: true }, { propertyName: "periodButtonRef", first: true, predicate: ["periodButton"], descendants: true, isSignal: true }], exportAs: ["comTimePicker"], ngImport: i0, template: `
4155
+ <div [class]="containerClasses()">
4156
+ <!-- Hours -->
4157
+ <input
4158
+ #hoursInput
4159
+ type="text"
4160
+ inputmode="numeric"
4161
+ role="spinbutton"
4162
+ [class]="segmentClasses()"
4163
+ [attr.aria-label]="'Hours'"
4164
+ [attr.aria-valuenow]="displayHours()"
4165
+ [attr.aria-valuemin]="is12Hour() ? 1 : 0"
4166
+ [attr.aria-valuemax]="is12Hour() ? 12 : 23"
4167
+ [value]="formattedHours()"
4168
+ [placeholder]="placeholder()"
4169
+ [disabled]="disabled()"
4170
+ maxlength="2"
4171
+ (keydown)="onSegmentKeydown($event, 'hours')"
4172
+ (input)="onSegmentInput($event, 'hours')"
4173
+ (focus)="onSegmentFocus('hours')"
4174
+ (blur)="onSegmentBlur('hours')"
4175
+ />
4176
+
4177
+ <span [class]="separatorClasses()" aria-hidden="true">:</span>
4178
+
4179
+ <!-- Minutes -->
4180
+ <input
4181
+ #minutesInput
4182
+ type="text"
4183
+ inputmode="numeric"
4184
+ role="spinbutton"
4185
+ [class]="segmentClasses()"
4186
+ [attr.aria-label]="'Minutes'"
4187
+ [attr.aria-valuenow]="internalValue()?.minutes ?? null"
4188
+ [attr.aria-valuemin]="0"
4189
+ [attr.aria-valuemax]="59"
4190
+ [value]="formattedMinutes()"
4191
+ [placeholder]="placeholder()"
4192
+ [disabled]="disabled()"
4193
+ maxlength="2"
4194
+ (keydown)="onSegmentKeydown($event, 'minutes')"
4195
+ (input)="onSegmentInput($event, 'minutes')"
4196
+ (focus)="onSegmentFocus('minutes')"
4197
+ (blur)="onSegmentBlur('minutes')"
4198
+ />
4199
+
4200
+ @if (showSeconds()) {
4201
+ <span [class]="separatorClasses()" aria-hidden="true">:</span>
4202
+
4203
+ <!-- Seconds -->
4204
+ <input
4205
+ #secondsInput
4206
+ type="text"
4207
+ inputmode="numeric"
4208
+ role="spinbutton"
4209
+ [class]="segmentClasses()"
4210
+ [attr.aria-label]="'Seconds'"
4211
+ [attr.aria-valuenow]="internalValue()?.seconds ?? null"
4212
+ [attr.aria-valuemin]="0"
4213
+ [attr.aria-valuemax]="59"
4214
+ [value]="formattedSeconds()"
4215
+ [placeholder]="placeholder()"
4216
+ [disabled]="disabled()"
4217
+ maxlength="2"
4218
+ (keydown)="onSegmentKeydown($event, 'seconds')"
4219
+ (input)="onSegmentInput($event, 'seconds')"
4220
+ (focus)="onSegmentFocus('seconds')"
4221
+ (blur)="onSegmentBlur('seconds')"
4222
+ />
4223
+ }
4224
+
4225
+ @if (is12Hour()) {
4226
+ <button
4227
+ #periodButton
4228
+ type="button"
4229
+ [class]="periodClasses()"
4230
+ [attr.aria-label]="'Toggle AM/PM, currently ' + period()"
4231
+ [disabled]="disabled()"
4232
+ (click)="togglePeriod()"
4233
+ (keydown)="onPeriodKeydown($event)"
4234
+ >
4235
+ {{ period() }}
4236
+ </button>
4237
+ }
4238
+ </div>
4239
+
4240
+ <div class="sr-only" aria-live="polite" aria-atomic="true">
4241
+ {{ liveAnnouncement() }}
4242
+ </div>
4243
+ `, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4244
+ }
4245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComTimePicker, decorators: [{
4246
+ type: Component,
4247
+ args: [{ selector: 'com-time-picker', exportAs: 'comTimePicker', template: `
4248
+ <div [class]="containerClasses()">
4249
+ <!-- Hours -->
4250
+ <input
4251
+ #hoursInput
4252
+ type="text"
4253
+ inputmode="numeric"
4254
+ role="spinbutton"
4255
+ [class]="segmentClasses()"
4256
+ [attr.aria-label]="'Hours'"
4257
+ [attr.aria-valuenow]="displayHours()"
4258
+ [attr.aria-valuemin]="is12Hour() ? 1 : 0"
4259
+ [attr.aria-valuemax]="is12Hour() ? 12 : 23"
4260
+ [value]="formattedHours()"
4261
+ [placeholder]="placeholder()"
4262
+ [disabled]="disabled()"
4263
+ maxlength="2"
4264
+ (keydown)="onSegmentKeydown($event, 'hours')"
4265
+ (input)="onSegmentInput($event, 'hours')"
4266
+ (focus)="onSegmentFocus('hours')"
4267
+ (blur)="onSegmentBlur('hours')"
4268
+ />
4269
+
4270
+ <span [class]="separatorClasses()" aria-hidden="true">:</span>
4271
+
4272
+ <!-- Minutes -->
4273
+ <input
4274
+ #minutesInput
4275
+ type="text"
4276
+ inputmode="numeric"
4277
+ role="spinbutton"
4278
+ [class]="segmentClasses()"
4279
+ [attr.aria-label]="'Minutes'"
4280
+ [attr.aria-valuenow]="internalValue()?.minutes ?? null"
4281
+ [attr.aria-valuemin]="0"
4282
+ [attr.aria-valuemax]="59"
4283
+ [value]="formattedMinutes()"
4284
+ [placeholder]="placeholder()"
4285
+ [disabled]="disabled()"
4286
+ maxlength="2"
4287
+ (keydown)="onSegmentKeydown($event, 'minutes')"
4288
+ (input)="onSegmentInput($event, 'minutes')"
4289
+ (focus)="onSegmentFocus('minutes')"
4290
+ (blur)="onSegmentBlur('minutes')"
4291
+ />
4292
+
4293
+ @if (showSeconds()) {
4294
+ <span [class]="separatorClasses()" aria-hidden="true">:</span>
4295
+
4296
+ <!-- Seconds -->
4297
+ <input
4298
+ #secondsInput
4299
+ type="text"
4300
+ inputmode="numeric"
4301
+ role="spinbutton"
4302
+ [class]="segmentClasses()"
4303
+ [attr.aria-label]="'Seconds'"
4304
+ [attr.aria-valuenow]="internalValue()?.seconds ?? null"
4305
+ [attr.aria-valuemin]="0"
4306
+ [attr.aria-valuemax]="59"
4307
+ [value]="formattedSeconds()"
4308
+ [placeholder]="placeholder()"
4309
+ [disabled]="disabled()"
4310
+ maxlength="2"
4311
+ (keydown)="onSegmentKeydown($event, 'seconds')"
4312
+ (input)="onSegmentInput($event, 'seconds')"
4313
+ (focus)="onSegmentFocus('seconds')"
4314
+ (blur)="onSegmentBlur('seconds')"
4315
+ />
4316
+ }
4317
+
4318
+ @if (is12Hour()) {
4319
+ <button
4320
+ #periodButton
4321
+ type="button"
4322
+ [class]="periodClasses()"
4323
+ [attr.aria-label]="'Toggle AM/PM, currently ' + period()"
4324
+ [disabled]="disabled()"
4325
+ (click)="togglePeriod()"
4326
+ (keydown)="onPeriodKeydown($event)"
4327
+ >
4328
+ {{ period() }}
4329
+ </button>
4330
+ }
4331
+ </div>
4332
+
4333
+ <div class="sr-only" aria-live="polite" aria-atomic="true">
4334
+ {{ liveAnnouncement() }}
4335
+ </div>
4336
+ `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
4337
+ class: 'com-time-picker-host inline-block',
4338
+ '[class.com-time-picker-disabled]': 'disabled()',
4339
+ '[attr.role]': '"group"',
4340
+ '[attr.aria-label]': 'ariaLabel() || "Time picker"',
4341
+ '[attr.aria-disabled]': 'disabled() || null',
4342
+ }, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
4343
+ }], ctorParameters: () => [], propDecorators: { hoursInputRef: [{ type: i0.ViewChild, args: ['hoursInput', { isSignal: true }] }], minutesInputRef: [{ type: i0.ViewChild, args: ['minutesInput', { isSignal: true }] }], secondsInputRef: [{ type: i0.ViewChild, args: ['secondsInput', { isSignal: true }] }], periodButtonRef: [{ type: i0.ViewChild, args: ['periodButton', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], secondStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondStep", required: false }] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], timeChange: [{ type: i0.Output, args: ["timeChange"] }] } });
4344
+
3374
4345
  /** Default position for the datepicker panel. */
3375
4346
  const DEFAULT_POSITIONS$1 = [
3376
4347
  // Below trigger, aligned start
@@ -3472,6 +4443,14 @@ class ComDatepicker {
3472
4443
  ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
3473
4444
  /** ID of element describing the input. */
3474
4445
  ariaDescribedBy = input(null, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
4446
+ /** Whether to show the time picker below the calendar. */
4447
+ showTimePicker = input(false, ...(ngDevMode ? [{ debugName: "showTimePicker" }] : []));
4448
+ /** 12h vs 24h format for the time picker. `null` = auto-detect. */
4449
+ use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
4450
+ /** Whether the time picker shows seconds. */
4451
+ showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
4452
+ /** Step interval for minutes in the time picker. */
4453
+ minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
3475
4454
  // ============ OUTPUTS ============
3476
4455
  /** Emitted when a date is selected. */
3477
4456
  dateChange = output();
@@ -3509,7 +4488,7 @@ class ComDatepicker {
3509
4488
  const value = this.internalValue();
3510
4489
  if (!value)
3511
4490
  return '';
3512
- return this.dateAdapter.format(value, this.dateFormat());
4491
+ return this.dateAdapter.format(value, this.effectiveDateFormat());
3513
4492
  }, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
3514
4493
  /** Computed trigger classes. */
3515
4494
  triggerClasses = computed(() => {
@@ -3551,6 +4530,28 @@ class ComDatepicker {
3551
4530
  clearButtonClasses = computed(() => {
3552
4531
  return datepickerFooterButtonVariants({ size: this.size(), variant: 'secondary' });
3553
4532
  }, ...(ngDevMode ? [{ debugName: "clearButtonClasses" }] : []));
4533
+ /** Time section divider classes. */
4534
+ timeSectionClasses = computed(() => {
4535
+ return timepickerSectionVariants({ size: this.size() });
4536
+ }, ...(ngDevMode ? [{ debugName: "timeSectionClasses" }] : []));
4537
+ /** Time value derived from the current date value. */
4538
+ timeValue = computed(() => {
4539
+ const date = this.internalValue();
4540
+ if (!date)
4541
+ return null;
4542
+ return createTimeValue(this.dateAdapter.getHours(date), this.dateAdapter.getMinutes(date), this.dateAdapter.getSeconds(date));
4543
+ }, ...(ngDevMode ? [{ debugName: "timeValue" }] : []));
4544
+ /** Effective display format — switches to dateTime when time picker is shown. */
4545
+ effectiveDateFormat = computed(() => {
4546
+ if (this.showTimePicker()) {
4547
+ return this.showSeconds() ? 'dateTimeLong' : 'dateTimeMedium';
4548
+ }
4549
+ return this.dateFormat();
4550
+ }, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
4551
+ /** Whether the panel should stay open (keepOpen or time picker shown). */
4552
+ effectiveKeepOpen = computed(() => {
4553
+ return this.keepOpen() || this.showTimePicker();
4554
+ }, ...(ngDevMode ? [{ debugName: "effectiveKeepOpen" }] : []));
3554
4555
  // ============ CVA CALLBACKS ============
3555
4556
  onChange = () => { };
3556
4557
  onTouched = () => { };
@@ -3663,7 +4664,7 @@ class ComDatepicker {
3663
4664
  selectToday() {
3664
4665
  const today = this.dateAdapter.today();
3665
4666
  this.updateValue(today);
3666
- if (!this.keepOpen()) {
4667
+ if (!this.effectiveKeepOpen()) {
3667
4668
  this.close();
3668
4669
  }
3669
4670
  }
@@ -3737,12 +4738,32 @@ class ComDatepicker {
3737
4738
  }
3738
4739
  }
3739
4740
  onDateSelected(date) {
3740
- this.updateValue(date);
3741
- if (!this.keepOpen()) {
4741
+ // Preserve time when selecting a new date if time picker is shown
4742
+ if (this.showTimePicker()) {
4743
+ const currentValue = this.internalValue();
4744
+ if (currentValue) {
4745
+ const withTime = this.dateAdapter.setTime(date, this.dateAdapter.getHours(currentValue), this.dateAdapter.getMinutes(currentValue), this.dateAdapter.getSeconds(currentValue));
4746
+ this.updateValue(withTime);
4747
+ }
4748
+ else {
4749
+ this.updateValue(date);
4750
+ }
4751
+ }
4752
+ else {
4753
+ this.updateValue(date);
4754
+ }
4755
+ if (!this.effectiveKeepOpen()) {
3742
4756
  this.close();
3743
4757
  }
3744
4758
  this.announce(`Selected ${this.dateAdapter.format(date, 'long')}`);
3745
4759
  }
4760
+ onTimeChange(time) {
4761
+ if (!time)
4762
+ return;
4763
+ const current = this.internalValue() ?? this.dateAdapter.today();
4764
+ const updated = this.dateAdapter.setTime(current, time.hours, time.minutes, time.seconds);
4765
+ this.updateValue(updated);
4766
+ }
3746
4767
  onActiveDateChange(date) {
3747
4768
  this.calendarActiveDate.set(date);
3748
4769
  }
@@ -3798,7 +4819,7 @@ class ComDatepicker {
3798
4819
  }
3799
4820
  return;
3800
4821
  }
3801
- const parsed = this.dateAdapter.parse(inputValue, this.dateFormat());
4822
+ const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
3802
4823
  if (parsed && this.dateAdapter.isValid(parsed)) {
3803
4824
  // Validate against min/max/filter
3804
4825
  if (this.isDateValid(parsed)) {
@@ -3833,7 +4854,7 @@ class ComDatepicker {
3833
4854
  this.liveAnnouncement.set(message);
3834
4855
  }
3835
4856
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDatepicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
3836
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDatepicker, isStandalone: true, selector: "com-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateChange: "dateChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-datepicker-disabled": "disabled()", "class.com-datepicker-open": "isOpen()" }, classAttribute: "com-datepicker-host inline-block" }, providers: [
4857
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDatepicker, isStandalone: true, selector: "com-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, showTimePicker: { classPropertyName: "showTimePicker", publicName: "showTimePicker", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateChange: "dateChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-datepicker-disabled": "disabled()", "class.com-datepicker-open": "isOpen()" }, classAttribute: "com-datepicker-host inline-block" }, providers: [
3837
4858
  SingleSelectionStrategy,
3838
4859
  { provide: CALENDAR_SELECTION_STRATEGY, useExisting: SingleSelectionStrategy },
3839
4860
  ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDatepicker"], ngImport: i0, template: `
@@ -3916,7 +4937,22 @@ class ComDatepicker {
3916
4937
  (activeDateChange)="onActiveDateChange($event)"
3917
4938
  />
3918
4939
 
3919
- @if (showTodayButton() || showFooterClearButton()) {
4940
+ @if (showTimePicker()) {
4941
+ <div [class]="timeSectionClasses()">
4942
+ <com-time-picker
4943
+ variant="embedded"
4944
+ [size]="size()"
4945
+ [value]="timeValue()"
4946
+ [use12HourFormat]="use12HourFormat()"
4947
+ [showSeconds]="showSeconds()"
4948
+ [minuteStep]="minuteStep()"
4949
+ [disabled]="disabled()"
4950
+ (timeChange)="onTimeChange($event)"
4951
+ />
4952
+ </div>
4953
+ }
4954
+
4955
+ @if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
3920
4956
  <div [class]="footerClasses()">
3921
4957
  @if (showTodayButton()) {
3922
4958
  <button
@@ -3936,6 +4972,15 @@ class ComDatepicker {
3936
4972
  Clear
3937
4973
  </button>
3938
4974
  }
4975
+ @if (showTimePicker()) {
4976
+ <button
4977
+ type="button"
4978
+ [class]="todayButtonClasses()"
4979
+ (click)="close()"
4980
+ >
4981
+ Done
4982
+ </button>
4983
+ }
3939
4984
  </div>
3940
4985
  }
3941
4986
  </div>
@@ -3945,7 +4990,7 @@ class ComDatepicker {
3945
4990
  <div class="sr-only" aria-live="polite" aria-atomic="true">
3946
4991
  {{ liveAnnouncement() }}
3947
4992
  </div>
3948
- `, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4993
+ `, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "component", type: ComTimePicker, selector: "com-time-picker", inputs: ["value", "disabled", "required", "showSeconds", "use12HourFormat", "minuteStep", "secondStep", "minTime", "maxTime", "variant", "size", "state", "ariaLabel", "class", "placeholder"], outputs: ["timeChange"], exportAs: ["comTimePicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3949
4994
  }
3950
4995
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDatepicker, decorators: [{
3951
4996
  type: Component,
@@ -4029,7 +5074,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4029
5074
  (activeDateChange)="onActiveDateChange($event)"
4030
5075
  />
4031
5076
 
4032
- @if (showTodayButton() || showFooterClearButton()) {
5077
+ @if (showTimePicker()) {
5078
+ <div [class]="timeSectionClasses()">
5079
+ <com-time-picker
5080
+ variant="embedded"
5081
+ [size]="size()"
5082
+ [value]="timeValue()"
5083
+ [use12HourFormat]="use12HourFormat()"
5084
+ [showSeconds]="showSeconds()"
5085
+ [minuteStep]="minuteStep()"
5086
+ [disabled]="disabled()"
5087
+ (timeChange)="onTimeChange($event)"
5088
+ />
5089
+ </div>
5090
+ }
5091
+
5092
+ @if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
4033
5093
  <div [class]="footerClasses()">
4034
5094
  @if (showTodayButton()) {
4035
5095
  <button
@@ -4049,6 +5109,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4049
5109
  Clear
4050
5110
  </button>
4051
5111
  }
5112
+ @if (showTimePicker()) {
5113
+ <button
5114
+ type="button"
5115
+ [class]="todayButtonClasses()"
5116
+ (click)="close()"
5117
+ >
5118
+ Done
5119
+ </button>
5120
+ }
4052
5121
  </div>
4053
5122
  }
4054
5123
  </div>
@@ -4063,6 +5132,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4063
5132
  A11yModule,
4064
5133
  ComCalendar,
4065
5134
  ComIcon,
5135
+ ComTimePicker,
4066
5136
  ], providers: [
4067
5137
  SingleSelectionStrategy,
4068
5138
  { provide: CALENDAR_SELECTION_STRATEGY, useExisting: SingleSelectionStrategy },
@@ -4071,7 +5141,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4071
5141
  '[class.com-datepicker-disabled]': 'disabled()',
4072
5142
  '[class.com-datepicker-open]': 'isOpen()',
4073
5143
  }, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
4074
- }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
5144
+ }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], showTimePicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimePicker", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
4075
5145
 
4076
5146
  /** Default position for the datepicker panel. */
4077
5147
  const DEFAULT_POSITIONS = [
@@ -4179,6 +5249,14 @@ class ComDateRangePicker {
4179
5249
  startAriaLabel = input(null, ...(ngDevMode ? [{ debugName: "startAriaLabel" }] : []));
4180
5250
  /** Accessible label for the end input. */
4181
5251
  endAriaLabel = input(null, ...(ngDevMode ? [{ debugName: "endAriaLabel" }] : []));
5252
+ /** Whether to show time pickers below the calendar. */
5253
+ showTimePicker = input(false, ...(ngDevMode ? [{ debugName: "showTimePicker" }] : []));
5254
+ /** 12h vs 24h format for the time pickers. `null` = auto-detect. */
5255
+ use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
5256
+ /** Whether the time pickers show seconds. */
5257
+ showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
5258
+ /** Step interval for minutes in the time pickers. */
5259
+ minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
4182
5260
  // ============ OUTPUTS ============
4183
5261
  /** Emitted when a complete range is selected. */
4184
5262
  rangeChange = output();
@@ -4230,14 +5308,14 @@ class ComDateRangePicker {
4230
5308
  const value = this.internalValue();
4231
5309
  if (!value?.start)
4232
5310
  return '';
4233
- return this.dateAdapter.format(value.start, this.dateFormat());
5311
+ return this.dateAdapter.format(value.start, this.effectiveDateFormat());
4234
5312
  }, ...(ngDevMode ? [{ debugName: "startDisplayValue" }] : []));
4235
5313
  /** Formatted end display value. */
4236
5314
  endDisplayValue = computed(() => {
4237
5315
  const value = this.internalValue();
4238
5316
  if (!value?.end)
4239
5317
  return '';
4240
- return this.dateAdapter.format(value.end, this.dateFormat());
5318
+ return this.dateAdapter.format(value.end, this.effectiveDateFormat());
4241
5319
  }, ...(ngDevMode ? [{ debugName: "endDisplayValue" }] : []));
4242
5320
  /** Computed trigger classes. */
4243
5321
  triggerClasses = computed(() => {
@@ -4283,6 +5361,39 @@ class ComDateRangePicker {
4283
5361
  clearButtonClasses = computed(() => {
4284
5362
  return datepickerFooterButtonVariants({ size: this.size(), variant: 'secondary' });
4285
5363
  }, ...(ngDevMode ? [{ debugName: "clearButtonClasses" }] : []));
5364
+ /** Time section divider classes. */
5365
+ timeSectionClasses = computed(() => {
5366
+ return timepickerSectionVariants({ size: this.size() });
5367
+ }, ...(ngDevMode ? [{ debugName: "timeSectionClasses" }] : []));
5368
+ /** Time label classes. */
5369
+ timeLabelClasses = computed(() => {
5370
+ return timepickerLabelVariants({ size: this.size() });
5371
+ }, ...(ngDevMode ? [{ debugName: "timeLabelClasses" }] : []));
5372
+ /** Start time value derived from the start date. */
5373
+ startTimeValue = computed(() => {
5374
+ const value = this.internalValue();
5375
+ if (!value?.start)
5376
+ return null;
5377
+ return createTimeValue(this.dateAdapter.getHours(value.start), this.dateAdapter.getMinutes(value.start), this.dateAdapter.getSeconds(value.start));
5378
+ }, ...(ngDevMode ? [{ debugName: "startTimeValue" }] : []));
5379
+ /** End time value derived from the end date. */
5380
+ endTimeValue = computed(() => {
5381
+ const value = this.internalValue();
5382
+ if (!value?.end)
5383
+ return null;
5384
+ return createTimeValue(this.dateAdapter.getHours(value.end), this.dateAdapter.getMinutes(value.end), this.dateAdapter.getSeconds(value.end));
5385
+ }, ...(ngDevMode ? [{ debugName: "endTimeValue" }] : []));
5386
+ /** Effective display format — switches to dateTime when time picker is shown. */
5387
+ effectiveDateFormat = computed(() => {
5388
+ if (this.showTimePicker()) {
5389
+ return this.showSeconds() ? 'dateTimeLong' : 'dateTimeMedium';
5390
+ }
5391
+ return this.dateFormat();
5392
+ }, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
5393
+ /** Whether the panel should stay open (keepOpen or time picker shown). */
5394
+ effectiveKeepOpen = computed(() => {
5395
+ return this.keepOpen() || this.showTimePicker();
5396
+ }, ...(ngDevMode ? [{ debugName: "effectiveKeepOpen" }] : []));
4286
5397
  // ============ CVA CALLBACKS ============
4287
5398
  onChange = () => { };
4288
5399
  onTouched = () => { };
@@ -4420,7 +5531,7 @@ class ComDateRangePicker {
4420
5531
  ? createDateRangeValue(today, currentValue.start)
4421
5532
  : createDateRangeValue(currentValue.start, today);
4422
5533
  this.updateValue(newRange);
4423
- if (!this.keepOpen()) {
5534
+ if (!this.effectiveKeepOpen()) {
4424
5535
  this.close();
4425
5536
  }
4426
5537
  }
@@ -4516,7 +5627,7 @@ class ComDateRangePicker {
4516
5627
  if (range.start && range.end) {
4517
5628
  // Complete range selected
4518
5629
  this.announce(`Range selected: ${this.formatDate(range.start)} to ${this.formatDate(range.end)}`);
4519
- if (!this.keepOpen()) {
5630
+ if (!this.effectiveKeepOpen()) {
4520
5631
  this.close();
4521
5632
  }
4522
5633
  }
@@ -4528,6 +5639,22 @@ class ComDateRangePicker {
4528
5639
  onActiveDateChange(date) {
4529
5640
  this.calendarActiveDate.set(date);
4530
5641
  }
5642
+ onStartTimeChange(time) {
5643
+ if (!time)
5644
+ return;
5645
+ const value = this.internalValue();
5646
+ const startDate = value?.start ?? this.dateAdapter.today();
5647
+ const updated = this.dateAdapter.setTime(startDate, time.hours, time.minutes, time.seconds);
5648
+ this.updateValue(createDateRangeValue(updated, value?.end ?? null));
5649
+ }
5650
+ onEndTimeChange(time) {
5651
+ if (!time)
5652
+ return;
5653
+ const value = this.internalValue();
5654
+ const endDate = value?.end ?? this.dateAdapter.today();
5655
+ const updated = this.dateAdapter.setTime(endDate, time.hours, time.minutes, time.seconds);
5656
+ this.updateValue(createDateRangeValue(value?.start ?? null, updated));
5657
+ }
4531
5658
  // ============ PRIVATE METHODS ============
4532
5659
  createOverlay() {
4533
5660
  if (this.overlayRef) {
@@ -4581,7 +5708,7 @@ class ComDateRangePicker {
4581
5708
  }
4582
5709
  return;
4583
5710
  }
4584
- const parsed = this.dateAdapter.parse(inputValue, this.dateFormat());
5711
+ const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
4585
5712
  if (parsed && this.dateAdapter.isValid(parsed) && this.isDateValid(parsed)) {
4586
5713
  // Ensure start <= end
4587
5714
  if (currentValue?.end && this.dateAdapter.compareDate(parsed, currentValue.end) > 0) {
@@ -4606,7 +5733,7 @@ class ComDateRangePicker {
4606
5733
  }
4607
5734
  return;
4608
5735
  }
4609
- const parsed = this.dateAdapter.parse(inputValue, this.dateFormat());
5736
+ const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
4610
5737
  if (parsed && this.dateAdapter.isValid(parsed) && this.isDateValid(parsed)) {
4611
5738
  // Ensure start <= end
4612
5739
  if (currentValue?.start && this.dateAdapter.compareDate(parsed, currentValue.start) < 0) {
@@ -4644,7 +5771,7 @@ class ComDateRangePicker {
4644
5771
  this.liveAnnouncement.set(message);
4645
5772
  }
4646
5773
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
4647
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDateRangePicker, isStandalone: true, selector: "com-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, startAriaLabel: { classPropertyName: "startAriaLabel", publicName: "startAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, endAriaLabel: { classPropertyName: "endAriaLabel", publicName: "endAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-date-range-picker-disabled": "disabled()", "class.com-date-range-picker-open": "isOpen()" }, classAttribute: "com-date-range-picker-host inline-block" }, providers: [
5774
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDateRangePicker, isStandalone: true, selector: "com-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", 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 }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, startAriaLabel: { classPropertyName: "startAriaLabel", publicName: "startAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, endAriaLabel: { classPropertyName: "endAriaLabel", publicName: "endAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, showTimePicker: { classPropertyName: "showTimePicker", publicName: "showTimePicker", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-date-range-picker-disabled": "disabled()", "class.com-date-range-picker-open": "isOpen()" }, classAttribute: "com-date-range-picker-host inline-block" }, providers: [
4648
5775
  RangeSelectionStrategy,
4649
5776
  { provide: CALENDAR_SELECTION_STRATEGY, useExisting: RangeSelectionStrategy },
4650
5777
  ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "startInputRef", first: true, predicate: ["startInputElement"], descendants: true, isSignal: true }, { propertyName: "endInputRef", first: true, predicate: ["endInputElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDateRangePicker"], ngImport: i0, template: `
@@ -4751,7 +5878,45 @@ class ComDateRangePicker {
4751
5878
  (activeDateChange)="onActiveDateChange($event)"
4752
5879
  />
4753
5880
 
4754
- @if (showTodayButton() || showFooterClearButton()) {
5881
+ @if (showTimePicker()) {
5882
+ <div [class]="timeSectionClasses()">
5883
+ <div class="flex items-center gap-3">
5884
+ <div class="flex flex-col gap-1">
5885
+ <span [class]="timeLabelClasses()">Start time</span>
5886
+ <com-time-picker
5887
+ variant="embedded"
5888
+ [size]="size()"
5889
+ [value]="startTimeValue()"
5890
+ [use12HourFormat]="use12HourFormat()"
5891
+ [showSeconds]="showSeconds()"
5892
+ [minuteStep]="minuteStep()"
5893
+ [disabled]="disabled()"
5894
+ ariaLabel="Start time"
5895
+ (timeChange)="onStartTimeChange($event)"
5896
+ />
5897
+ </div>
5898
+ <span class="text-muted-foreground mt-5">
5899
+ <com-icon name="arrow-right" [size]="iconSize()" />
5900
+ </span>
5901
+ <div class="flex flex-col gap-1">
5902
+ <span [class]="timeLabelClasses()">End time</span>
5903
+ <com-time-picker
5904
+ variant="embedded"
5905
+ [size]="size()"
5906
+ [value]="endTimeValue()"
5907
+ [use12HourFormat]="use12HourFormat()"
5908
+ [showSeconds]="showSeconds()"
5909
+ [minuteStep]="minuteStep()"
5910
+ [disabled]="disabled()"
5911
+ ariaLabel="End time"
5912
+ (timeChange)="onEndTimeChange($event)"
5913
+ />
5914
+ </div>
5915
+ </div>
5916
+ </div>
5917
+ }
5918
+
5919
+ @if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
4755
5920
  <div [class]="footerClasses()">
4756
5921
  @if (showTodayButton()) {
4757
5922
  <button
@@ -4771,6 +5936,15 @@ class ComDateRangePicker {
4771
5936
  Clear
4772
5937
  </button>
4773
5938
  }
5939
+ @if (showTimePicker()) {
5940
+ <button
5941
+ type="button"
5942
+ [class]="todayButtonClasses()"
5943
+ (click)="close()"
5944
+ >
5945
+ Done
5946
+ </button>
5947
+ }
4774
5948
  </div>
4775
5949
  }
4776
5950
  </div>
@@ -4780,7 +5954,7 @@ class ComDateRangePicker {
4780
5954
  <div class="sr-only" aria-live="polite" aria-atomic="true">
4781
5955
  {{ liveAnnouncement() }}
4782
5956
  </div>
4783
- `, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5957
+ `, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "component", type: ComTimePicker, selector: "com-time-picker", inputs: ["value", "disabled", "required", "showSeconds", "use12HourFormat", "minuteStep", "secondStep", "minTime", "maxTime", "variant", "size", "state", "ariaLabel", "class", "placeholder"], outputs: ["timeChange"], exportAs: ["comTimePicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4784
5958
  }
4785
5959
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDateRangePicker, decorators: [{
4786
5960
  type: Component,
@@ -4888,7 +6062,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4888
6062
  (activeDateChange)="onActiveDateChange($event)"
4889
6063
  />
4890
6064
 
4891
- @if (showTodayButton() || showFooterClearButton()) {
6065
+ @if (showTimePicker()) {
6066
+ <div [class]="timeSectionClasses()">
6067
+ <div class="flex items-center gap-3">
6068
+ <div class="flex flex-col gap-1">
6069
+ <span [class]="timeLabelClasses()">Start time</span>
6070
+ <com-time-picker
6071
+ variant="embedded"
6072
+ [size]="size()"
6073
+ [value]="startTimeValue()"
6074
+ [use12HourFormat]="use12HourFormat()"
6075
+ [showSeconds]="showSeconds()"
6076
+ [minuteStep]="minuteStep()"
6077
+ [disabled]="disabled()"
6078
+ ariaLabel="Start time"
6079
+ (timeChange)="onStartTimeChange($event)"
6080
+ />
6081
+ </div>
6082
+ <span class="text-muted-foreground mt-5">
6083
+ <com-icon name="arrow-right" [size]="iconSize()" />
6084
+ </span>
6085
+ <div class="flex flex-col gap-1">
6086
+ <span [class]="timeLabelClasses()">End time</span>
6087
+ <com-time-picker
6088
+ variant="embedded"
6089
+ [size]="size()"
6090
+ [value]="endTimeValue()"
6091
+ [use12HourFormat]="use12HourFormat()"
6092
+ [showSeconds]="showSeconds()"
6093
+ [minuteStep]="minuteStep()"
6094
+ [disabled]="disabled()"
6095
+ ariaLabel="End time"
6096
+ (timeChange)="onEndTimeChange($event)"
6097
+ />
6098
+ </div>
6099
+ </div>
6100
+ </div>
6101
+ }
6102
+
6103
+ @if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
4892
6104
  <div [class]="footerClasses()">
4893
6105
  @if (showTodayButton()) {
4894
6106
  <button
@@ -4908,6 +6120,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4908
6120
  Clear
4909
6121
  </button>
4910
6122
  }
6123
+ @if (showTimePicker()) {
6124
+ <button
6125
+ type="button"
6126
+ [class]="todayButtonClasses()"
6127
+ (click)="close()"
6128
+ >
6129
+ Done
6130
+ </button>
6131
+ }
4911
6132
  </div>
4912
6133
  }
4913
6134
  </div>
@@ -4922,6 +6143,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4922
6143
  A11yModule,
4923
6144
  ComCalendar,
4924
6145
  ComIcon,
6146
+ ComTimePicker,
4925
6147
  ], providers: [
4926
6148
  RangeSelectionStrategy,
4927
6149
  { provide: CALENDAR_SELECTION_STRATEGY, useExisting: RangeSelectionStrategy },
@@ -4930,12 +6152,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4930
6152
  '[class.com-date-range-picker-disabled]': 'disabled()',
4931
6153
  '[class.com-date-range-picker-open]': 'isOpen()',
4932
6154
  }, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
4933
- }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], startInputRef: [{ type: i0.ViewChild, args: ['startInputElement', { isSignal: true }] }], endInputRef: [{ type: i0.ViewChild, args: ['endInputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], startAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAriaLabel", required: false }] }], endAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "endAriaLabel", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
6155
+ }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], startInputRef: [{ type: i0.ViewChild, args: ['startInputElement', { isSignal: true }] }], endInputRef: [{ type: i0.ViewChild, args: ['endInputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], startAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAriaLabel", required: false }] }], endAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "endAriaLabel", required: false }] }], showTimePicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimePicker", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
4934
6156
 
4935
6157
  /**
4936
6158
  * Datepicker components public API.
4937
6159
  */
4938
6160
 
6161
+ /**
6162
+ * TimePicker component public API.
6163
+ */
6164
+
4939
6165
  /**
4940
6166
  * ngx-com/components/calendar
4941
6167
  * Calendar component public API
@@ -4945,5 +6171,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
4945
6171
  * Generated bundle index. Do not edit.
4946
6172
  */
4947
6173
 
4948
- export { CALENDAR_SELECTION_STRATEGY, CalendarSelectionStrategy, CalendarViewBase, ComCalendar, ComCalendarCell, ComCalendarHeader, ComCalendarMonthView, ComCalendarMultiYearView, ComCalendarYearView, ComDateRangePicker, ComDatepicker, DATE_ADAPTER, DAYS_PER_WEEK, DateAdapter, MONTHS_PER_ROW, MultiSelectionStrategy, NativeDateAdapter, RangeSelectionStrategy, SingleSelectionStrategy, WEEKS_PER_MONTH, WeekSelectionStrategy, YEARS_PER_PAGE, YEARS_PER_ROW, calendarCellVariants, calendarCellWrapperVariants, calendarHeaderButtonVariants, calendarHeaderVariants, calendarVariants, createCalendarCell, createDateRange, createDateRangeValue, createGrid, datepickerClearVariants, datepickerDisabledVariants, datepickerFooterButtonVariants, datepickerFooterVariants, datepickerIconVariants, datepickerInputVariants, datepickerPanelVariants, datepickerRangeSeparatorVariants, datepickerTriggerVariants, generateDatepickerId, getMultiYearStartingYear, getWeekdayHeaders, isDateDisabled, isMonthDisabled, isYearDisabled, navigateGrid, provideMultiSelectionStrategy, provideNativeDateAdapter, provideRangeSelectionStrategy, provideSingleSelectionStrategy, provideWeekSelectionStrategy };
6174
+ export { CALENDAR_SELECTION_STRATEGY, CalendarSelectionStrategy, CalendarViewBase, ComCalendar, ComCalendarCell, ComCalendarHeader, ComCalendarMonthView, ComCalendarMultiYearView, ComCalendarYearView, ComDateRangePicker, ComDatepicker, ComTimePicker, DATE_ADAPTER, DAYS_PER_WEEK, DateAdapter, MONTHS_PER_ROW, MultiSelectionStrategy, NativeDateAdapter, RangeSelectionStrategy, SingleSelectionStrategy, WEEKS_PER_MONTH, WeekSelectionStrategy, YEARS_PER_PAGE, YEARS_PER_ROW, calendarCellVariants, calendarCellWrapperVariants, calendarHeaderButtonVariants, calendarHeaderVariants, calendarVariants, compareTime, createCalendarCell, createDateRange, createDateRangeValue, createGrid, createTimeValue, datepickerClearVariants, datepickerDisabledVariants, datepickerFooterButtonVariants, datepickerFooterVariants, datepickerIconVariants, datepickerInputVariants, datepickerPanelVariants, datepickerRangeSeparatorVariants, datepickerTriggerVariants, generateDatepickerId, generateTimePickerId, getMultiYearStartingYear, getWeekdayHeaders, isDateDisabled, isMonthDisabled, isYearDisabled, navigateGrid, provideMultiSelectionStrategy, provideNativeDateAdapter, provideRangeSelectionStrategy, provideSingleSelectionStrategy, provideWeekSelectionStrategy, timepickerContainerVariants, timepickerDisabledVariants, timepickerLabelVariants, timepickerPeriodVariants, timepickerSectionVariants, timepickerSegmentVariants, timepickerSeparatorVariants };
4949
6175
  //# sourceMappingURL=ngx-com-components-calendar.mjs.map