@gloww/gloww 20.0.0-beta.32 → 20.0.0-beta.33

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.
@@ -3626,6 +3626,9 @@ class DatetimeComponent {
3626
3626
  'YYYY-MM-DDTHH:mm:ss',
3627
3627
  'YYYY-MM-DDTHH:mm'
3628
3628
  ]; }
3629
+ static { this.CLOCK_CENTER = 50; }
3630
+ static { this.CLOCK_OUTER_RADIUS = 40; }
3631
+ static { this.CLOCK_INNER_RADIUS = 27; }
3629
3632
  constructor(locale) {
3630
3633
  this.locale = locale;
3631
3634
  this._value = null;
@@ -3637,7 +3640,12 @@ class DatetimeComponent {
3637
3640
  this.hourControl = new FormControl('00', { nonNullable: true });
3638
3641
  this.minuteControl = new FormControl('00', { nonNullable: true });
3639
3642
  this.secondControl = new FormControl('00', { nonNullable: true });
3643
+ this.hourMarkers = this.buildHourMarkers();
3644
+ this.minuteMarkers = this.buildUnitMarkers();
3645
+ this.secondMarkers = this.buildUnitMarkers();
3640
3646
  this.isDisabled = false;
3647
+ this.isClockOpen = false;
3648
+ this.clockStep = 'hour';
3641
3649
  this.onChange = () => { };
3642
3650
  this.onTouched = () => { };
3643
3651
  this.dateControl.valueChanges.subscribe(() => this.emitCurrentValue());
@@ -3673,6 +3681,7 @@ class DatetimeComponent {
3673
3681
  }
3674
3682
  clear() {
3675
3683
  this._value = null;
3684
+ this.isClockOpen = false;
3676
3685
  this.dateControl.setValue(null, { emitEvent: false });
3677
3686
  this.hourControl.setValue('00', { emitEvent: false });
3678
3687
  this.minuteControl.setValue('00', { emitEvent: false });
@@ -3683,37 +3692,31 @@ class DatetimeComponent {
3683
3692
  markTouched() {
3684
3693
  this.onTouched();
3685
3694
  }
3686
- get timePickerValue() {
3687
- const hour = this.normalizeTimePartValue(this.hourControl.value, 23, true);
3688
- const minute = this.normalizeTimePartValue(this.minuteControl.value, 59, true);
3689
- const second = this.normalizeTimePartValue(this.secondControl.value, 59, true);
3690
- return this.showSeconds ? `${hour}:${minute}:${second}` : `${hour}:${minute}`;
3695
+ get timeSummary() {
3696
+ return this.showSeconds
3697
+ ? `${this.normalizeTimePartValue(this.hourControl.value, 23, true)}:${this.normalizeTimePartValue(this.minuteControl.value, 59, true)}:${this.normalizeTimePartValue(this.secondControl.value, 59, true)}`
3698
+ : `${this.normalizeTimePartValue(this.hourControl.value, 23, true)}:${this.normalizeTimePartValue(this.minuteControl.value, 59, true)}`;
3691
3699
  }
3692
- openNativeTimePicker(input) {
3700
+ get clockTitle() {
3701
+ switch (this.clockStep) {
3702
+ case 'hour':
3703
+ return 'Hours';
3704
+ case 'minute':
3705
+ return 'Minutes';
3706
+ default:
3707
+ return 'Seconds';
3708
+ }
3709
+ }
3710
+ openClock() {
3693
3711
  if (this.isDisabled) {
3694
3712
  return;
3695
3713
  }
3696
- const picker = input;
3697
- if (typeof picker.showPicker === 'function') {
3698
- picker.showPicker();
3699
- }
3700
- else {
3701
- picker.focus();
3702
- picker.click();
3703
- }
3714
+ this.isClockOpen = true;
3715
+ this.clockStep = 'hour';
3704
3716
  this.onTouched();
3705
3717
  }
3706
- onNativeTimeSelected(value) {
3707
- if (!value) {
3708
- return;
3709
- }
3710
- const parts = value.split(':');
3711
- this.hourControl.setValue(this.normalizeTimePartValue(parts[0], 23, true), { emitEvent: false });
3712
- this.minuteControl.setValue(this.normalizeTimePartValue(parts[1], 59, true), { emitEvent: false });
3713
- if (this.showSeconds) {
3714
- this.secondControl.setValue(this.normalizeTimePartValue(parts[2], 59, true), { emitEvent: false });
3715
- }
3716
- this.emitCurrentValue();
3718
+ closeClock() {
3719
+ this.isClockOpen = false;
3717
3720
  this.onTouched();
3718
3721
  }
3719
3722
  onTimePartInput(part) {
@@ -3729,6 +3732,41 @@ class DatetimeComponent {
3729
3732
  this.emitCurrentValue();
3730
3733
  this.onTouched();
3731
3734
  }
3735
+ selectClockHour(value) {
3736
+ this.hourControl.setValue(value.toString().padStart(2, '0'), { emitEvent: false });
3737
+ this.emitCurrentValue();
3738
+ this.clockStep = 'minute';
3739
+ this.onTouched();
3740
+ }
3741
+ selectClockMinute(value) {
3742
+ this.minuteControl.setValue(value.toString().padStart(2, '0'), { emitEvent: false });
3743
+ this.emitCurrentValue();
3744
+ if (this.showSeconds) {
3745
+ this.clockStep = 'second';
3746
+ }
3747
+ else {
3748
+ this.closeClock();
3749
+ }
3750
+ this.onTouched();
3751
+ }
3752
+ selectClockSecond(value) {
3753
+ this.secondControl.setValue(value.toString().padStart(2, '0'), { emitEvent: false });
3754
+ this.emitCurrentValue();
3755
+ this.closeClock();
3756
+ this.onTouched();
3757
+ }
3758
+ goToClockStep(step) {
3759
+ this.clockStep = step;
3760
+ }
3761
+ isHourSelected(value) {
3762
+ return this.toNumber(this.hourControl.value) === value;
3763
+ }
3764
+ isMinuteSelected(value) {
3765
+ return this.toNumber(this.minuteControl.value) === value;
3766
+ }
3767
+ isSecondSelected(value) {
3768
+ return this.toNumber(this.secondControl.value) === value;
3769
+ }
3732
3770
  setValueFromOutside(value, emit) {
3733
3771
  const normalized = this.normalizeDateValue(value);
3734
3772
  this._value = normalized;
@@ -3804,6 +3842,23 @@ class DatetimeComponent {
3804
3842
  }
3805
3843
  return null;
3806
3844
  }
3845
+ buildHourMarkers() {
3846
+ return Array.from({ length: 24 }, (_, index) => this.buildClockMarker(index, index < 12 ? DatetimeComponent.CLOCK_OUTER_RADIUS : DatetimeComponent.CLOCK_INNER_RADIUS, index.toString().padStart(2, '0')));
3847
+ }
3848
+ buildUnitMarkers() {
3849
+ return Array.from({ length: 60 }, (_, index) => this.buildClockMarker(index, DatetimeComponent.CLOCK_OUTER_RADIUS, index % 5 === 0 ? index.toString().padStart(2, '0') : ''));
3850
+ }
3851
+ buildClockMarker(index, radius, label) {
3852
+ const angle = ((index % 12) / 12) * (Math.PI * 2) - (Math.PI / 2);
3853
+ const x = DatetimeComponent.CLOCK_CENTER + Math.cos(angle) * radius;
3854
+ const y = DatetimeComponent.CLOCK_CENTER + Math.sin(angle) * radius;
3855
+ return {
3856
+ value: index,
3857
+ label,
3858
+ left: `${x}%`,
3859
+ top: `${y}%`
3860
+ };
3861
+ }
3807
3862
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatetimeComponent, deps: [{ token: MAT_DATE_LOCALE, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
3808
3863
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DatetimeComponent, isStandalone: true, selector: "gloww-datetime", inputs: { _value: ["value", "_value"], display: "display", placeHolder: "placeHolder", mode: "mode", showSeconds: "showSeconds" }, providers: [
3809
3864
  {
@@ -3811,7 +3866,7 @@ class DatetimeComponent {
3811
3866
  multi: true,
3812
3867
  useExisting: forwardRef(() => DatetimeComponent)
3813
3868
  }
3814
- ], ngImport: i0, template: "<div class=\"datetime-wrapper\" [class.datetime-mode]=\"isDateTime\" [class.has-seconds]=\"showSeconds\">\n <mat-form-field class=\"date-field\">\n @if (display) {\n <mat-label>{{ display }}</mat-label>\n }\n <input\n matInput\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeHolder\"\n [formControl]=\"dateControl\"\n [disabled]=\"isDisabled\"\n (dateChange)=\"markTouched()\"\n (blur)=\"markTouched()\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n\n @if (isDateTime) {\n <div class=\"middle-actions\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Clear date and time\"\n aria-label=\"Clear date and time\"\n (click)=\"clear()\">\n <mat-icon>ink_eraser</mat-icon>\n </button>\n\n <input\n #nativeTimePicker\n class=\"native-time-picker\"\n type=\"time\"\n [step]=\"showSeconds ? 1 : 60\"\n [value]=\"timePickerValue\"\n [disabled]=\"isDisabled\"\n (change)=\"onNativeTimeSelected(nativeTimePicker.value)\">\n\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Open time picker\"\n aria-label=\"Open time picker\"\n (click)=\"openNativeTimePicker(nativeTimePicker)\">\n <mat-icon>schedule</mat-icon>\n </button>\n </div>\n\n <div class=\"time-row\">\n <mat-form-field class=\"time-field\">\n <mat-label>HH</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"23\"\n inputmode=\"numeric\"\n [formControl]=\"hourControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('hour')\"\n (blur)=\"onTimePartBlur('hour')\">\n </mat-form-field>\n\n <mat-form-field class=\"time-field\">\n <mat-label>MM</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"minuteControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('minute')\"\n (blur)=\"onTimePartBlur('minute')\">\n </mat-form-field>\n\n @if (showSeconds) {\n <mat-form-field class=\"time-field\">\n <mat-label>SS</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"secondControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('second')\"\n (blur)=\"onTimePartBlur('second')\">\n </mat-form-field>\n }\n </div>\n }\n</div>\n", styles: [".datetime-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.date-field,.time-field{width:100%}.middle-actions{display:flex;align-items:center;gap:4px;justify-content:flex-start}.icon-action{flex:0 0 auto}.time-row{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.native-time-picker{position:absolute;pointer-events:none;opacity:0;width:0;height:0}@media(min-width:720px){.time-row{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:960px){.datetime-wrapper.datetime-mode{display:grid;align-items:start;gap:8px;grid-template-columns:minmax(240px,2fr) auto repeat(2,minmax(84px,96px))}.datetime-wrapper.datetime-mode.has-seconds{grid-template-columns:minmax(240px,2fr) auto repeat(3,minmax(84px,96px))}.datetime-wrapper.datetime-mode .date-field{margin-bottom:0}.datetime-wrapper.datetime-mode .middle-actions{align-self:start;padding-top:4px}.datetime-wrapper.datetime-mode .time-row{display:contents}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: MatFormField$1, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel$1, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
3869
+ ], ngImport: i0, template: "<div class=\"datetime-wrapper\" [class.datetime-mode]=\"isDateTime\" [class.has-seconds]=\"showSeconds\">\n <mat-form-field class=\"date-field\">\n @if (display) {\n <mat-label>{{ display }}</mat-label>\n }\n <input\n matInput\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeHolder\"\n [formControl]=\"dateControl\"\n [disabled]=\"isDisabled\"\n (dateChange)=\"markTouched()\"\n (blur)=\"markTouched()\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n\n @if (isDateTime) {\n <div class=\"middle-actions\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Clear date and time\"\n aria-label=\"Clear date and time\"\n (click)=\"clear()\">\n <i class=\"fal fa-eraser\"></i>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Open time clock\"\n aria-label=\"Open time clock\"\n (click)=\"openClock()\">\n <i class=\"fal fa-clock\"></i>\n </button>\n </div>\n\n <div class=\"time-row\">\n <mat-form-field class=\"time-field\">\n <mat-label>HH</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"23\"\n inputmode=\"numeric\"\n [formControl]=\"hourControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('hour')\"\n (blur)=\"onTimePartBlur('hour')\">\n </mat-form-field>\n\n <mat-form-field class=\"time-field\">\n <mat-label>MM</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"minuteControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('minute')\"\n (blur)=\"onTimePartBlur('minute')\">\n </mat-form-field>\n\n @if (showSeconds) {\n <mat-form-field class=\"time-field\">\n <mat-label>SS</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"secondControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('second')\"\n (blur)=\"onTimePartBlur('second')\">\n </mat-form-field>\n }\n </div>\n\n @if (isClockOpen) {\n <div class=\"clock-panel\">\n <div class=\"clock-panel-header\">\n <div class=\"clock-panel-title\">{{ clockTitle }}</div>\n <button\n mat-button\n type=\"button\"\n class=\"clock-close\"\n [disabled]=\"isDisabled\"\n (click)=\"closeClock()\">\n Close\n </button>\n </div>\n\n <div class=\"clock-summary\">\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'hour'\" (click)=\"goToClockStep('hour')\">\n {{ hourControl.value || '00' }}\n </button>\n <span>:</span>\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'minute'\" (click)=\"goToClockStep('minute')\">\n {{ minuteControl.value || '00' }}\n </button>\n @if (showSeconds) {\n <span>:</span>\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'second'\" (click)=\"goToClockStep('second')\">\n {{ secondControl.value || '00' }}\n </button>\n }\n </div>\n\n <div class=\"clock-face\">\n @if (clockStep === 'hour') {\n @for (marker of hourMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker\"\n [class.selected]=\"isHourSelected(marker.value)\"\n [class.inner-ring]=\"marker.value >= 12\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockHour(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n @if (clockStep === 'minute') {\n @for (marker of minuteMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker clock-unit-marker\"\n [class.selected]=\"isMinuteSelected(marker.value)\"\n [class.major]=\"!!marker.label\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockMinute(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n @if (clockStep === 'second') {\n @for (marker of secondMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker clock-unit-marker\"\n [class.selected]=\"isSecondSelected(marker.value)\"\n [class.major]=\"!!marker.label\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockSecond(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n <div class=\"clock-center-dot\"></div>\n </div>\n\n <div class=\"clock-help\">\n @if (clockStep === 'hour') {\n <span>Outer ring 00-11, inner ring 12-23.</span>\n }\n @if (clockStep === 'minute') {\n <span>Choose the minute.</span>\n }\n @if (clockStep === 'second') {\n <span>Choose the second.</span>\n }\n </div>\n\n <div class=\"clock-footer\">\n <span>{{ timeSummary }}</span>\n </div>\n </div>\n }\n }\n</div>\n", styles: [".datetime-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.date-field,.time-field{width:100%}.middle-actions{display:flex;align-items:center;gap:4px;justify-content:flex-start}.icon-action{flex:0 0 auto}.icon-action i{font-size:1rem;line-height:1}.time-row{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.clock-panel{display:flex;flex-direction:column;gap:10px;padding:12px;border:1px solid rgba(0,0,0,.12);border-radius:16px;background:#fff}.clock-panel-header,.clock-summary,.clock-footer{display:flex;align-items:center;justify-content:space-between;gap:8px}.clock-panel-title{font-size:.95rem;font-weight:600}.clock-summary{justify-content:center;font-size:1.1rem}.clock-step{min-width:52px;font-weight:600}.clock-step.active{background:#1976d21f}.clock-face{position:relative;align-self:center;width:min(100%,280px);aspect-ratio:1;border-radius:50%;background:radial-gradient(circle at center,rgba(25,118,210,.08) 0 16%,transparent 16% 100%),radial-gradient(circle at center,transparent 0 61%,rgba(25,118,210,.08) 61% 62%,transparent 62% 100%),radial-gradient(circle at center,#0000000a 0 100%)}.clock-marker{position:absolute;transform:translate(-50%,-50%);width:38px;height:38px;min-width:38px;padding:0;border-radius:50%;font-size:.72rem;line-height:1}.clock-marker.inner-ring{width:34px;height:34px;min-width:34px;font-size:.68rem}.clock-unit-marker{width:24px;height:24px;min-width:24px;font-size:.58rem;color:transparent}.clock-unit-marker.major{width:34px;height:34px;min-width:34px;font-size:.68rem;color:inherit}.clock-marker.selected{background:#1976d2;color:#fff}.clock-center-dot{position:absolute;top:50%;left:50%;width:12px;height:12px;border-radius:50%;transform:translate(-50%,-50%);background:#1976d2}.clock-help,.clock-footer{font-size:.78rem;color:#000000ad}@media(min-width:720px){.time-row{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:960px){.datetime-wrapper.datetime-mode{display:grid;align-items:start;gap:8px;grid-template-columns:minmax(240px,2fr) auto repeat(2,minmax(84px,96px))}.datetime-wrapper.datetime-mode.has-seconds{grid-template-columns:minmax(240px,2fr) auto repeat(3,minmax(84px,96px))}.datetime-wrapper.datetime-mode .date-field{margin-bottom:0}.datetime-wrapper.datetime-mode .middle-actions{align-self:start;padding-top:4px}.datetime-wrapper.datetime-mode .time-row{display:contents}.datetime-wrapper.datetime-mode .clock-panel{grid-column:1/-1}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: MatFormField$1, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel$1, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] }); }
3815
3870
  }
3816
3871
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatetimeComponent, decorators: [{
3817
3872
  type: Component,
@@ -3821,7 +3876,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
3821
3876
  multi: true,
3822
3877
  useExisting: forwardRef(() => DatetimeComponent)
3823
3878
  }
3824
- ], imports: [ReactiveFormsModule, MatFormField$1, MatLabel$1, MatInput, MatDatepickerInput, MatDatepickerToggle, MatDatepicker, MatSuffix, MatButton, MatIcon], template: "<div class=\"datetime-wrapper\" [class.datetime-mode]=\"isDateTime\" [class.has-seconds]=\"showSeconds\">\n <mat-form-field class=\"date-field\">\n @if (display) {\n <mat-label>{{ display }}</mat-label>\n }\n <input\n matInput\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeHolder\"\n [formControl]=\"dateControl\"\n [disabled]=\"isDisabled\"\n (dateChange)=\"markTouched()\"\n (blur)=\"markTouched()\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n\n @if (isDateTime) {\n <div class=\"middle-actions\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Clear date and time\"\n aria-label=\"Clear date and time\"\n (click)=\"clear()\">\n <mat-icon>ink_eraser</mat-icon>\n </button>\n\n <input\n #nativeTimePicker\n class=\"native-time-picker\"\n type=\"time\"\n [step]=\"showSeconds ? 1 : 60\"\n [value]=\"timePickerValue\"\n [disabled]=\"isDisabled\"\n (change)=\"onNativeTimeSelected(nativeTimePicker.value)\">\n\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Open time picker\"\n aria-label=\"Open time picker\"\n (click)=\"openNativeTimePicker(nativeTimePicker)\">\n <mat-icon>schedule</mat-icon>\n </button>\n </div>\n\n <div class=\"time-row\">\n <mat-form-field class=\"time-field\">\n <mat-label>HH</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"23\"\n inputmode=\"numeric\"\n [formControl]=\"hourControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('hour')\"\n (blur)=\"onTimePartBlur('hour')\">\n </mat-form-field>\n\n <mat-form-field class=\"time-field\">\n <mat-label>MM</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"minuteControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('minute')\"\n (blur)=\"onTimePartBlur('minute')\">\n </mat-form-field>\n\n @if (showSeconds) {\n <mat-form-field class=\"time-field\">\n <mat-label>SS</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"secondControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('second')\"\n (blur)=\"onTimePartBlur('second')\">\n </mat-form-field>\n }\n </div>\n }\n</div>\n", styles: [".datetime-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.date-field,.time-field{width:100%}.middle-actions{display:flex;align-items:center;gap:4px;justify-content:flex-start}.icon-action{flex:0 0 auto}.time-row{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.native-time-picker{position:absolute;pointer-events:none;opacity:0;width:0;height:0}@media(min-width:720px){.time-row{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:960px){.datetime-wrapper.datetime-mode{display:grid;align-items:start;gap:8px;grid-template-columns:minmax(240px,2fr) auto repeat(2,minmax(84px,96px))}.datetime-wrapper.datetime-mode.has-seconds{grid-template-columns:minmax(240px,2fr) auto repeat(3,minmax(84px,96px))}.datetime-wrapper.datetime-mode .date-field{margin-bottom:0}.datetime-wrapper.datetime-mode .middle-actions{align-self:start;padding-top:4px}.datetime-wrapper.datetime-mode .time-row{display:contents}}\n"] }]
3879
+ ], imports: [ReactiveFormsModule, MatFormField$1, MatLabel$1, MatInput, MatDatepickerInput, MatDatepickerToggle, MatDatepicker, MatSuffix, MatButton], template: "<div class=\"datetime-wrapper\" [class.datetime-mode]=\"isDateTime\" [class.has-seconds]=\"showSeconds\">\n <mat-form-field class=\"date-field\">\n @if (display) {\n <mat-label>{{ display }}</mat-label>\n }\n <input\n matInput\n [matDatepicker]=\"picker\"\n [placeholder]=\"placeHolder\"\n [formControl]=\"dateControl\"\n [disabled]=\"isDisabled\"\n (dateChange)=\"markTouched()\"\n (blur)=\"markTouched()\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n\n @if (isDateTime) {\n <div class=\"middle-actions\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Clear date and time\"\n aria-label=\"Clear date and time\"\n (click)=\"clear()\">\n <i class=\"fal fa-eraser\"></i>\n </button>\n\n <button\n mat-icon-button\n type=\"button\"\n class=\"icon-action\"\n [disabled]=\"isDisabled\"\n title=\"Open time clock\"\n aria-label=\"Open time clock\"\n (click)=\"openClock()\">\n <i class=\"fal fa-clock\"></i>\n </button>\n </div>\n\n <div class=\"time-row\">\n <mat-form-field class=\"time-field\">\n <mat-label>HH</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"23\"\n inputmode=\"numeric\"\n [formControl]=\"hourControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('hour')\"\n (blur)=\"onTimePartBlur('hour')\">\n </mat-form-field>\n\n <mat-form-field class=\"time-field\">\n <mat-label>MM</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"minuteControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('minute')\"\n (blur)=\"onTimePartBlur('minute')\">\n </mat-form-field>\n\n @if (showSeconds) {\n <mat-form-field class=\"time-field\">\n <mat-label>SS</mat-label>\n <input\n matInput\n type=\"number\"\n min=\"0\"\n max=\"59\"\n inputmode=\"numeric\"\n [formControl]=\"secondControl\"\n [disabled]=\"isDisabled\"\n (input)=\"onTimePartInput('second')\"\n (blur)=\"onTimePartBlur('second')\">\n </mat-form-field>\n }\n </div>\n\n @if (isClockOpen) {\n <div class=\"clock-panel\">\n <div class=\"clock-panel-header\">\n <div class=\"clock-panel-title\">{{ clockTitle }}</div>\n <button\n mat-button\n type=\"button\"\n class=\"clock-close\"\n [disabled]=\"isDisabled\"\n (click)=\"closeClock()\">\n Close\n </button>\n </div>\n\n <div class=\"clock-summary\">\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'hour'\" (click)=\"goToClockStep('hour')\">\n {{ hourControl.value || '00' }}\n </button>\n <span>:</span>\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'minute'\" (click)=\"goToClockStep('minute')\">\n {{ minuteControl.value || '00' }}\n </button>\n @if (showSeconds) {\n <span>:</span>\n <button mat-button type=\"button\" class=\"clock-step\" [class.active]=\"clockStep === 'second'\" (click)=\"goToClockStep('second')\">\n {{ secondControl.value || '00' }}\n </button>\n }\n </div>\n\n <div class=\"clock-face\">\n @if (clockStep === 'hour') {\n @for (marker of hourMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker\"\n [class.selected]=\"isHourSelected(marker.value)\"\n [class.inner-ring]=\"marker.value >= 12\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockHour(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n @if (clockStep === 'minute') {\n @for (marker of minuteMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker clock-unit-marker\"\n [class.selected]=\"isMinuteSelected(marker.value)\"\n [class.major]=\"!!marker.label\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockMinute(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n @if (clockStep === 'second') {\n @for (marker of secondMarkers; track marker.value) {\n <button\n mat-icon-button\n type=\"button\"\n class=\"clock-marker clock-unit-marker\"\n [class.selected]=\"isSecondSelected(marker.value)\"\n [class.major]=\"!!marker.label\"\n [style.left]=\"marker.left\"\n [style.top]=\"marker.top\"\n (click)=\"selectClockSecond(marker.value)\">\n {{ marker.label }}\n </button>\n }\n }\n\n <div class=\"clock-center-dot\"></div>\n </div>\n\n <div class=\"clock-help\">\n @if (clockStep === 'hour') {\n <span>Outer ring 00-11, inner ring 12-23.</span>\n }\n @if (clockStep === 'minute') {\n <span>Choose the minute.</span>\n }\n @if (clockStep === 'second') {\n <span>Choose the second.</span>\n }\n </div>\n\n <div class=\"clock-footer\">\n <span>{{ timeSummary }}</span>\n </div>\n </div>\n }\n }\n</div>\n", styles: [".datetime-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.date-field,.time-field{width:100%}.middle-actions{display:flex;align-items:center;gap:4px;justify-content:flex-start}.icon-action{flex:0 0 auto}.icon-action i{font-size:1rem;line-height:1}.time-row{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.clock-panel{display:flex;flex-direction:column;gap:10px;padding:12px;border:1px solid rgba(0,0,0,.12);border-radius:16px;background:#fff}.clock-panel-header,.clock-summary,.clock-footer{display:flex;align-items:center;justify-content:space-between;gap:8px}.clock-panel-title{font-size:.95rem;font-weight:600}.clock-summary{justify-content:center;font-size:1.1rem}.clock-step{min-width:52px;font-weight:600}.clock-step.active{background:#1976d21f}.clock-face{position:relative;align-self:center;width:min(100%,280px);aspect-ratio:1;border-radius:50%;background:radial-gradient(circle at center,rgba(25,118,210,.08) 0 16%,transparent 16% 100%),radial-gradient(circle at center,transparent 0 61%,rgba(25,118,210,.08) 61% 62%,transparent 62% 100%),radial-gradient(circle at center,#0000000a 0 100%)}.clock-marker{position:absolute;transform:translate(-50%,-50%);width:38px;height:38px;min-width:38px;padding:0;border-radius:50%;font-size:.72rem;line-height:1}.clock-marker.inner-ring{width:34px;height:34px;min-width:34px;font-size:.68rem}.clock-unit-marker{width:24px;height:24px;min-width:24px;font-size:.58rem;color:transparent}.clock-unit-marker.major{width:34px;height:34px;min-width:34px;font-size:.68rem;color:inherit}.clock-marker.selected{background:#1976d2;color:#fff}.clock-center-dot{position:absolute;top:50%;left:50%;width:12px;height:12px;border-radius:50%;transform:translate(-50%,-50%);background:#1976d2}.clock-help,.clock-footer{font-size:.78rem;color:#000000ad}@media(min-width:720px){.time-row{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:960px){.datetime-wrapper.datetime-mode{display:grid;align-items:start;gap:8px;grid-template-columns:minmax(240px,2fr) auto repeat(2,minmax(84px,96px))}.datetime-wrapper.datetime-mode.has-seconds{grid-template-columns:minmax(240px,2fr) auto repeat(3,minmax(84px,96px))}.datetime-wrapper.datetime-mode .date-field{margin-bottom:0}.datetime-wrapper.datetime-mode .middle-actions{align-self:start;padding-top:4px}.datetime-wrapper.datetime-mode .time-row{display:contents}.datetime-wrapper.datetime-mode .clock-panel{grid-column:1/-1}}\n"] }]
3825
3880
  }], ctorParameters: () => [{ type: undefined, decorators: [{
3826
3881
  type: Optional
3827
3882
  }, {