shirkasoft-ui-components 1.3.7 → 1.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -13
- package/fesm2022/shirkasoft-ui-components-button.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-button.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-confirm-dialog.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-confirm-dialog.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-date-picker.mjs +90 -9
- package/fesm2022/shirkasoft-ui-components-date-picker.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-loading.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-loading.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-modal.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-modal.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-notification.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-notification.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-price-input.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-price-input.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-select.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-select.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-table.mjs +198 -12
- package/fesm2022/shirkasoft-ui-components-table.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-tabs.mjs +7 -12
- package/fesm2022/shirkasoft-ui-components-tabs.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-tag.mjs +3 -3
- package/fesm2022/shirkasoft-ui-components-tag.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-text-field.mjs +2 -2
- package/fesm2022/shirkasoft-ui-components-text-field.mjs.map +1 -1
- package/fesm2022/shirkasoft-ui-components-toggle.mjs +61 -24
- package/fesm2022/shirkasoft-ui-components-toggle.mjs.map +1 -1
- package/package.json +2 -2
- package/src/theme.css +80 -0
- package/types/shirkasoft-ui-components-date-picker.d.ts +24 -4
- package/types/shirkasoft-ui-components-table.d.ts +86 -9
- package/types/shirkasoft-ui-components-toggle.d.ts +7 -1
|
@@ -18,6 +18,22 @@ import { TranslocoService } from '@jsverse/transloco';
|
|
|
18
18
|
* min/max constraints and locale-aware labels.
|
|
19
19
|
*/
|
|
20
20
|
class DatePickerComponent {
|
|
21
|
+
/** Localized range label for a week (e.g. '2 — 8 feb'). */
|
|
22
|
+
formatWeekRange(start, end) {
|
|
23
|
+
const loc = this.locale();
|
|
24
|
+
const dayFmt = new Intl.DateTimeFormat(loc, { day: 'numeric' });
|
|
25
|
+
const monthFmt = new Intl.DateTimeFormat(loc, { month: 'short' });
|
|
26
|
+
const startLabel = `${dayFmt.format(start)} ${monthFmt.format(start).replace('.', '')}`;
|
|
27
|
+
if (start.getMonth() !== end.getMonth() || start.getFullYear() !== end.getFullYear()) {
|
|
28
|
+
const year = start.getFullYear() !== end.getFullYear() ? ` ${end.getFullYear()}` : '';
|
|
29
|
+
return `${startLabel} — ${dayFmt.format(end)} ${monthFmt.format(end).replace('.', '')}${year}`;
|
|
30
|
+
}
|
|
31
|
+
return `${startLabel} — ${dayFmt.format(end)}`;
|
|
32
|
+
}
|
|
33
|
+
/** Localized label for a week row ('Semana N' / 'Week N'). */
|
|
34
|
+
weekLabel(index) {
|
|
35
|
+
return this.locale() === 'en' ? `Week ${index}` : `Semana ${index}`;
|
|
36
|
+
}
|
|
21
37
|
constructor() {
|
|
22
38
|
this.elementRef = inject(ElementRef);
|
|
23
39
|
this.cdr = inject(ChangeDetectorRef);
|
|
@@ -25,8 +41,10 @@ class DatePickerComponent {
|
|
|
25
41
|
this.transloco = inject(TranslocoService);
|
|
26
42
|
/** HTML id for the input (for label/for pairing). */
|
|
27
43
|
this.id = input('', ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
28
|
-
/** Granularity of the picker ('date' | 'month' | 'year'). */
|
|
44
|
+
/** Granularity of the picker ('date' | 'week' | 'month' | 'year'). */
|
|
29
45
|
this.view = input('date', ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
46
|
+
/** First day of the week (0=Sunday ... 6=Saturday), used by week view. */
|
|
47
|
+
this.weekStart = input(0, ...(ngDevMode ? [{ debugName: "weekStart" }] : /* istanbul ignore next */ []));
|
|
30
48
|
/** Label shown above the input. */
|
|
31
49
|
this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
32
50
|
/** Placeholder of the input. */
|
|
@@ -188,6 +206,10 @@ class DatePickerComponent {
|
|
|
188
206
|
label = fmt.format(new Date(y, m - 1, 1));
|
|
189
207
|
label = label.charAt(0).toUpperCase() + label.slice(1);
|
|
190
208
|
}
|
|
209
|
+
else if (v === 'week') {
|
|
210
|
+
const start = new Date(datePart + 'T12:00:00');
|
|
211
|
+
label = this.formatWeekRange(start, new Date(start.getFullYear(), start.getMonth(), start.getDate() + 6));
|
|
212
|
+
}
|
|
191
213
|
else {
|
|
192
214
|
const fmt = new Intl.DateTimeFormat(this.locale(), {
|
|
193
215
|
dateStyle: 'long',
|
|
@@ -234,11 +256,31 @@ class DatePickerComponent {
|
|
|
234
256
|
days.push(i);
|
|
235
257
|
return days;
|
|
236
258
|
}, ...(ngDevMode ? [{ debugName: "calendarDays" }] : /* istanbul ignore next */ []));
|
|
259
|
+
/** Weeks of the viewed month (rows aligned to `weekStart`), for week view. */
|
|
260
|
+
this.monthWeeks = computed(() => {
|
|
261
|
+
const year = this.viewYear();
|
|
262
|
+
const month = this.viewMonth();
|
|
263
|
+
const ws = this.weekStart();
|
|
264
|
+
const first = new Date(year, month, 1);
|
|
265
|
+
const last = new Date(year, month + 1, 0);
|
|
266
|
+
const anchor = new Date(first.getFullYear(), first.getMonth(), first.getDate() - ((first.getDay() - ws + 7) % 7));
|
|
267
|
+
const weeks = [];
|
|
268
|
+
let cursor = anchor;
|
|
269
|
+
let index = 0;
|
|
270
|
+
while (cursor.getTime() <= last.getTime()) {
|
|
271
|
+
index++;
|
|
272
|
+
const start = cursor;
|
|
273
|
+
const end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 6);
|
|
274
|
+
weeks.push({ index, start, end, range: this.formatWeekRange(start, end) });
|
|
275
|
+
cursor = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 7);
|
|
276
|
+
}
|
|
277
|
+
return weeks;
|
|
278
|
+
}, ...(ngDevMode ? [{ debugName: "monthWeeks" }] : /* istanbul ignore next */ []));
|
|
237
279
|
/** Whether the prev navigation button is allowed by `minValue`. */
|
|
238
280
|
this.canGoPrev = computed(() => {
|
|
239
281
|
const v = this.currentView();
|
|
240
282
|
const min = this.minValue();
|
|
241
|
-
if (v === 'date') {
|
|
283
|
+
if (v === 'date' || v === 'week') {
|
|
242
284
|
if (!min)
|
|
243
285
|
return true;
|
|
244
286
|
const prev = new Date(this.viewYear(), this.viewMonth() - 1, 1);
|
|
@@ -256,7 +298,7 @@ class DatePickerComponent {
|
|
|
256
298
|
this.canGoNext = computed(() => {
|
|
257
299
|
const v = this.currentView();
|
|
258
300
|
const max = this.maxValue();
|
|
259
|
-
if (v === 'date') {
|
|
301
|
+
if (v === 'date' || v === 'week') {
|
|
260
302
|
if (!max)
|
|
261
303
|
return true;
|
|
262
304
|
const next = new Date(this.viewYear(), this.viewMonth() + 1, 1);
|
|
@@ -367,7 +409,7 @@ class DatePickerComponent {
|
|
|
367
409
|
}
|
|
368
410
|
else {
|
|
369
411
|
this.syncViewToValue();
|
|
370
|
-
this.currentView.set('year');
|
|
412
|
+
this.currentView.set(this.view() === 'week' ? 'week' : 'year');
|
|
371
413
|
this.selectedYearValue.set(null);
|
|
372
414
|
this.selectedMonthValue.set(null);
|
|
373
415
|
this.clockMode.set('hours');
|
|
@@ -399,6 +441,11 @@ class DatePickerComponent {
|
|
|
399
441
|
else if (v === 'month') {
|
|
400
442
|
this.viewYear.set(Number(datePart.split('-')[0]));
|
|
401
443
|
}
|
|
444
|
+
else if (v === 'week') {
|
|
445
|
+
const d = new Date(datePart + 'T12:00:00');
|
|
446
|
+
this.viewYear.set(d.getFullYear());
|
|
447
|
+
this.viewMonth.set(d.getMonth());
|
|
448
|
+
}
|
|
402
449
|
else {
|
|
403
450
|
const d = new Date(datePart + 'T12:00:00');
|
|
404
451
|
this.viewYear.set(d.getFullYear());
|
|
@@ -494,7 +541,17 @@ class DatePickerComponent {
|
|
|
494
541
|
}
|
|
495
542
|
this.setValue(value);
|
|
496
543
|
}
|
|
497
|
-
/**
|
|
544
|
+
/** Selects a week - emits its start date (YYYY-MM-DD). */
|
|
545
|
+
selectWeek(start) {
|
|
546
|
+
const value = `${start.getFullYear()}-` +
|
|
547
|
+
`${String(start.getMonth() + 1).padStart(2, '0')}-` +
|
|
548
|
+
`${String(start.getDate()).padStart(2, '0')}`;
|
|
549
|
+
if (this.showTime()) {
|
|
550
|
+
this.pendingDate.set(value);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
this.setValue(value);
|
|
554
|
+
}
|
|
498
555
|
setValue(value, close = true) {
|
|
499
556
|
this._value.set(value);
|
|
500
557
|
this.onChange(value);
|
|
@@ -761,6 +818,9 @@ class DatePickerComponent {
|
|
|
761
818
|
return 'YYYY';
|
|
762
819
|
if (this.view() === 'month')
|
|
763
820
|
return 'MM/YYYY';
|
|
821
|
+
if (this.view() === 'week') {
|
|
822
|
+
return this.locale() === 'en' ? 'Week · MM/YYYY' : 'Semana · MM/YYYY';
|
|
823
|
+
}
|
|
764
824
|
return this.inputFormat();
|
|
765
825
|
}
|
|
766
826
|
/** Handles text input in the date field. */
|
|
@@ -817,6 +877,8 @@ class DatePickerComponent {
|
|
|
817
877
|
if (this.timeOnly()) {
|
|
818
878
|
return this.parseTimeOnly(clean);
|
|
819
879
|
}
|
|
880
|
+
if (this.view() === 'week')
|
|
881
|
+
return null;
|
|
820
882
|
if (this.view() === 'year') {
|
|
821
883
|
const y = Number(parts[0]);
|
|
822
884
|
if (parts.length === 1 && y >= 1900 && y <= 2100)
|
|
@@ -899,6 +961,25 @@ class DatePickerComponent {
|
|
|
899
961
|
this.viewMonth() === now.getMonth() &&
|
|
900
962
|
day === now.getDate());
|
|
901
963
|
}
|
|
964
|
+
/** ISO date (YYYY-MM-DD) of the week start containing the given date. */
|
|
965
|
+
weekStartISO(date) {
|
|
966
|
+
const ws = this.weekStart();
|
|
967
|
+
const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - ((date.getDay() - ws + 7) % 7));
|
|
968
|
+
return (`${start.getFullYear()}-` +
|
|
969
|
+
`${String(start.getMonth() + 1).padStart(2, '0')}-` +
|
|
970
|
+
`${String(start.getDate()).padStart(2, '0')}`);
|
|
971
|
+
}
|
|
972
|
+
/** Whether the given week row contains the displayed/selected date. */
|
|
973
|
+
isSelectedWeek(start) {
|
|
974
|
+
const date = this.displayedDate();
|
|
975
|
+
if (!date)
|
|
976
|
+
return false;
|
|
977
|
+
return this.weekStartISO(new Date(date + 'T12:00:00')) === this.weekStartISO(start);
|
|
978
|
+
}
|
|
979
|
+
/** Whether the given week row contains today's date. */
|
|
980
|
+
isCurrentWeek(start) {
|
|
981
|
+
return this.weekStartISO(new Date()) === this.weekStartISO(start);
|
|
982
|
+
}
|
|
902
983
|
/** Whether the given month matches the selected month and year. */
|
|
903
984
|
isSelectedMonth(monthIndex) {
|
|
904
985
|
return this.selectedMonthValue() === monthIndex;
|
|
@@ -927,13 +1008,13 @@ class DatePickerComponent {
|
|
|
927
1008
|
this.cdr.markForCheck();
|
|
928
1009
|
}
|
|
929
1010
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
930
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: DatePickerComponent, isStandalone: true, selector: "shk-date-picker", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, timeOnly: { classPropertyName: "timeOnly", publicName: "timeOnly", isSignal: true, isRequired: false, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: false, transformFunction: null }, hourFormat: { classPropertyName: "hourFormat", publicName: "hourFormat", 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 } }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, providers: [
|
|
1011
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.23", type: DatePickerComponent, isStandalone: true, selector: "shk-date-picker", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, weekStart: { classPropertyName: "weekStart", publicName: "weekStart", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, timeOnly: { classPropertyName: "timeOnly", publicName: "timeOnly", isSignal: true, isRequired: false, transformFunction: null }, showTime: { classPropertyName: "showTime", publicName: "showTime", isSignal: true, isRequired: false, transformFunction: null }, hourFormat: { classPropertyName: "hourFormat", publicName: "hourFormat", 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 } }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, providers: [
|
|
931
1012
|
{
|
|
932
1013
|
provide: NG_VALUE_ACCESSOR,
|
|
933
1014
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
934
1015
|
multi: true,
|
|
935
1016
|
},
|
|
936
|
-
], ngImport: i0, template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n <div class=\"relative\">\n <input\n [id]=\"id()\"\n type=\"text\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isTyping() ? typedValue() : displayLabel()\"\n (input)=\"onInputText($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$any($event.target).blur()\"\n (keydown.escape)=\"cancelTyping()\"\n (click)=\"toggle()\"\n class=\"date-input-field\"\n [ngClass]=\"{\n 'input-error': shouldShowError() || typingValid() === false,\n 'input-valid': wasFixedError() || typingValid() === true,\n }\"\n [attr.aria-invalid]=\"shouldShowError()\"\n [attr.aria-describedby]=\"shouldShowError() ? id() + '-error' : null\"\n />\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n class=\"w-4 h-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n </div>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <!-- DATE VIEW -->\n @if (!timeOnly() && currentView() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n <!-- MONTH VIEW -->\n @if (!timeOnly() && currentView() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedMonthValue() === $index,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && selectedMonthValue() !== $index,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedMonthValue() !== $index && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n <!-- YEAR VIEW -->\n @if (!timeOnly() && currentView() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedYearValue() === year,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && selectedYearValue() !== year,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedYearValue() !== year && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n\n <!-- ANALOG CLOCK TIME PICKER -->\n @if (timeOnly() || showTime()) {\n <div class=\"mt-3 pt-3 _shk-border dark:[border-color:var(--shk-surface-200)]\">\n <!-- Clock display time -->\n <div class=\"text-center mb-2\">\n <span class=\"text-lg font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ clockDisplayTime() }}\n </span>\n </div>\n\n <!-- Analog clock face -->\n <div class=\"clock-container\">\n <svg\n viewBox=\"0 0 200 200\"\n class=\"w-full h-full cursor-pointer\"\n (click)=\"onClockClick($event, clockMode())\"\n >\n <!-- Clock face background -->\n <circle cx=\"100\" cy=\"100\" r=\"96\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\"\n class=\"_shk-text-surface-200 dark:[color:var(--shk-surface-200)]\" />\n\n <!-- Minute markers -->\n @if (clockMode() === 'minutes') {\n @for (i of [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59]; track i) {\n <line\n [attr.x1]=\"clockMinuteMarker(i).x1\"\n [attr.y1]=\"clockMinuteMarker(i).y1\"\n [attr.x2]=\"clockMinuteMarker(i).x2\"\n [attr.y2]=\"clockMinuteMarker(i).y2\"\n [attr.stroke-width]=\"i % 5 === 0 ? 2 : 1\"\n [class]=\"i % 5 === 0 ? '_shk-text-surface-500 dark:[color:var(--shk-surface-500)]' : '_shk-text-surface-300 dark:[color:var(--shk-surface-400)]'\"\n stroke=\"currentColor\"\n />\n }\n <!-- Minute numbers (00, 05, 10, ...) -->\n @for (m of [0,5,10,15,20,25,30,35,40,45,50,55]; track m) {\n <text\n [attr.x]=\"clockMinutePos(m).x\"\n [attr.y]=\"clockMinutePos(m).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-[9px] _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\"\n [class._shk-text-primary]=\"viewMinute() === m\"\n >\n {{ m.toString().padStart(2, '0') }}\n </text>\n }\n }\n\n <!-- Hour numbers -->\n @if (clockMode() === 'hours') {\n @for (h of clockHours(); track h) {\n <text\n [attr.x]=\"clockNumberPos(h).x\"\n [attr.y]=\"clockNumberPos(h).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-sm font-medium\"\n [class._shk-text-primary]=\"isClockHourSelected(h)\"\n [class._shk-text-surface-700]=\"!isClockHourSelected(h)\"\n >\n {{ h }}\n </text>\n }\n }\n\n <!-- Clock hand -->\n <line\n x1=\"100\" y1=\"100\"\n [attr.x2]=\"clockHandLine(60).x2\"\n [attr.y2]=\"clockHandLine(60).y2\"\n class=\"_shk-text-primary\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n\n <!-- Center dot -->\n <circle cx=\"100\" cy=\"100\" r=\"4\" class=\"fill-current _shk-text-primary\" />\n </svg>\n </div>\n\n <!-- Mode toggle: Hours / Minutes -->\n <div class=\"clock-mode-toggle\">\n <button\n type=\"button\"\n (click)=\"clockMode.set('hours')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'hours'\"\n >\n {{ 'Horas' }}\n </button>\n <button\n type=\"button\"\n (click)=\"clockMode.set('minutes')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'minutes'\"\n >\n {{ 'Minutos' }}\n </button>\n </div>\n\n <!-- AM/PM toggle for 12h format -->\n @if (hourFormat() === '12') {\n <div class=\"flex items-center justify-center gap-2 mt-2\">\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('AM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'AM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'AM'\n }\"\n >\n AM\n </button>\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('PM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'PM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'PM'\n }\"\n >\n PM\n </button>\n </div>\n }\n\n <!-- Seconds selector (if enabled) -->\n @if (showSeconds()) {\n <div class=\"flex items-center justify-center gap-1 mt-2\">\n <span class=\"text-xs _shk-text-surface-400\">Seg:</span>\n <select\n class=\"px-2 py-1 text-xs _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md\"\n [value]=\"viewSecond()\"\n (change)=\"onSecondChange($event)\"\n aria-label=\"Segundos\"\n >\n @for (seconds of secondsRange(); track seconds) {\n <option [value]=\"seconds\">{{ minutesLabel(seconds) }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Confirm button -->\n <button\n type=\"button\"\n (click)=\"confirmTime()\"\n class=\"mt-3 w-full py-2 text-sm _shk-bg-primary _shk-text-white rounded-lg hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n {{ timeOnly() ? 'Confirmar' : 'Introducir hora' }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div [id]=\"id() + '-error'\" class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", styles: [".clock-container{position:relative;width:200px;height:200px;margin:0 auto}.clock-face{width:100%;height:100%;border-radius:50%;border:2px solid var(--shk-surface-200);position:relative;background-color:var(--shk-surface-50)}.dark .clock-face{border-color:var(--shk-surface-200);background-color:var(--shk-surface-100)}.clock-number{position:absolute;width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:500;border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:background-color .15s,color .15s;-webkit-user-select:none;user-select:none;color:var(--shk-surface-700)}.dark .clock-number{color:var(--shk-surface-700)}.clock-number:hover{background-color:var(--shk-surface-100)}.dark .clock-number:hover{background-color:var(--shk-surface-200)}.clock-number.selected{background-color:var(--shk-primary-500);color:#fff}.clock-number.current{font-weight:700}.clock-hand{position:absolute;bottom:50%;left:50%;width:2px;background-color:var(--shk-primary-500);transform-origin:bottom center;border-radius:1px;pointer-events:none;transition:transform .2s ease-out}.clock-center{position:absolute;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:var(--shk-primary-500);transform:translate(-50%,-50%);pointer-events:none;z-index:2}.clock-minute-marker{position:absolute;width:1px;height:8px;background-color:var(--shk-surface-300);top:6px;left:50%;transform-origin:center 94px}.dark .clock-minute-marker{background-color:var(--shk-surface-400)}.clock-minute-marker.major{width:2px;height:12px;background-color:var(--shk-surface-400)}.dark .clock-minute-marker.major{background-color:var(--shk-surface-500)}.clock-mode-toggle{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-top:.75rem}.clock-mode-btn{padding:.25rem .75rem;font-size:.75rem;font-weight:500;border-radius:9999px;cursor:pointer;transition:background-color .15s,color .15s;border:none;background:transparent;color:var(--shk-surface-500)}.dark .clock-mode-btn{color:var(--shk-surface-400)}.clock-mode-btn.active{background-color:var(--shk-primary-500);color:#fff}.clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-100)}.dark .clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-200)}.date-input-field{width:100%;padding:.5rem 2.5rem .5rem .75rem;font-size:.875rem;border-radius:.5rem;outline:none;transition:border-color .15s,box-shadow .15s;background-color:var(--shk-surface-50);color:var(--shk-surface-700);border:1px solid var(--shk-surface-200)}.dark .date-input-field{background-color:var(--shk-surface-100);color:var(--shk-surface-700);border-color:var(--shk-surface-200)}.date-input-field::placeholder{color:var(--shk-surface-400)}.dark .date-input-field::placeholder{color:var(--shk-surface-400)}.date-input-field:focus{border-color:var(--shk-primary-500);box-shadow:0 0 0 1px var(--shk-primary-500)}.date-input-field:disabled{opacity:.5;cursor:not-allowed}.date-input-field.input-error{border-color:#ef4444}.date-input-field.input-error:focus{border-color:#ef4444;box-shadow:0 0 0 1px #ef4444}.date-input-field.input-valid{border-color:#22c55e}.date-input-field.input-valid:focus{border-color:#22c55e;box-shadow:0 0 0 1px #22c55e}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1017
|
+
], ngImport: i0, template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n <div class=\"relative\">\n <input\n [id]=\"id()\"\n type=\"text\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isTyping() ? typedValue() : displayLabel()\"\n (input)=\"onInputText($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$any($event.target).blur()\"\n (keydown.escape)=\"cancelTyping()\"\n (click)=\"toggle()\"\n class=\"date-input-field\"\n [ngClass]=\"{\n 'input-error': shouldShowError() || typingValid() === false,\n 'input-valid': wasFixedError() || typingValid() === true,\n }\"\n [attr.aria-invalid]=\"shouldShowError()\"\n [attr.aria-describedby]=\"shouldShowError() ? id() + '-error' : null\"\n />\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n class=\"w-4 h-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n </div>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <!-- DATE VIEW -->\n @if (!timeOnly() && currentView() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n <!-- WEEK VIEW -->\n @if (!timeOnly() && currentView() === 'week') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"space-y-1\">\n @for (week of monthWeeks(); track week.index) {\n <button\n type=\"button\"\n (click)=\"selectWeek(week.start)\"\n class=\"w-full flex items-center justify-between py-1.5 px-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedWeek(week.start),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentWeek(week.start) && !isSelectedWeek(week.start),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedWeek(week.start) && !isCurrentWeek(week.start),\n }\"\n >\n <span class=\"font-medium\">{{ weekLabel(week.index) }}</span>\n <span class=\"text-xs opacity-80\">{{ week.range }}</span>\n </button>\n }\n </div>\n }\n\n <!-- MONTH VIEW -->\n @if (!timeOnly() && currentView() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedMonthValue() === $index,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && selectedMonthValue() !== $index,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedMonthValue() !== $index && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n <!-- YEAR VIEW -->\n @if (!timeOnly() && currentView() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedYearValue() === year,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && selectedYearValue() !== year,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedYearValue() !== year && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n\n <!-- ANALOG CLOCK TIME PICKER -->\n @if (timeOnly() || showTime()) {\n <div class=\"mt-3 pt-3 _shk-border dark:[border-color:var(--shk-surface-200)]\">\n <!-- Clock display time -->\n <div class=\"text-center mb-2\">\n <span class=\"text-lg font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ clockDisplayTime() }}\n </span>\n </div>\n\n <!-- Analog clock face -->\n <div class=\"clock-container\">\n <svg\n viewBox=\"0 0 200 200\"\n class=\"w-full h-full cursor-pointer\"\n (click)=\"onClockClick($event, clockMode())\"\n >\n <!-- Clock face background -->\n <circle cx=\"100\" cy=\"100\" r=\"96\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\"\n class=\"_shk-text-surface-200 dark:[color:var(--shk-surface-200)]\" />\n\n <!-- Minute markers -->\n @if (clockMode() === 'minutes') {\n @for (i of [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59]; track i) {\n <line\n [attr.x1]=\"clockMinuteMarker(i).x1\"\n [attr.y1]=\"clockMinuteMarker(i).y1\"\n [attr.x2]=\"clockMinuteMarker(i).x2\"\n [attr.y2]=\"clockMinuteMarker(i).y2\"\n [attr.stroke-width]=\"i % 5 === 0 ? 2 : 1\"\n [class]=\"i % 5 === 0 ? '_shk-text-surface-500 dark:[color:var(--shk-surface-500)]' : '_shk-text-surface-300 dark:[color:var(--shk-surface-400)]'\"\n stroke=\"currentColor\"\n />\n }\n <!-- Minute numbers (00, 05, 10, ...) -->\n @for (m of [0,5,10,15,20,25,30,35,40,45,50,55]; track m) {\n <text\n [attr.x]=\"clockMinutePos(m).x\"\n [attr.y]=\"clockMinutePos(m).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-[9px] _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\"\n [class._shk-text-primary]=\"viewMinute() === m\"\n >\n {{ m.toString().padStart(2, '0') }}\n </text>\n }\n }\n\n <!-- Hour numbers -->\n @if (clockMode() === 'hours') {\n @for (h of clockHours(); track h) {\n <text\n [attr.x]=\"clockNumberPos(h).x\"\n [attr.y]=\"clockNumberPos(h).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-sm font-medium\"\n [class._shk-text-primary]=\"isClockHourSelected(h)\"\n [class._shk-text-surface-700]=\"!isClockHourSelected(h)\"\n >\n {{ h }}\n </text>\n }\n }\n\n <!-- Clock hand -->\n <line\n x1=\"100\" y1=\"100\"\n [attr.x2]=\"clockHandLine(60).x2\"\n [attr.y2]=\"clockHandLine(60).y2\"\n class=\"_shk-text-primary\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n\n <!-- Center dot -->\n <circle cx=\"100\" cy=\"100\" r=\"4\" class=\"fill-current _shk-text-primary\" />\n </svg>\n </div>\n\n <!-- Mode toggle: Hours / Minutes -->\n <div class=\"clock-mode-toggle\">\n <button\n type=\"button\"\n (click)=\"clockMode.set('hours')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'hours'\"\n >\n {{ 'Horas' }}\n </button>\n <button\n type=\"button\"\n (click)=\"clockMode.set('minutes')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'minutes'\"\n >\n {{ 'Minutos' }}\n </button>\n </div>\n\n <!-- AM/PM toggle for 12h format -->\n @if (hourFormat() === '12') {\n <div class=\"flex items-center justify-center gap-2 mt-2\">\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('AM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'AM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'AM'\n }\"\n >\n AM\n </button>\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('PM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'PM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'PM'\n }\"\n >\n PM\n </button>\n </div>\n }\n\n <!-- Seconds selector (if enabled) -->\n @if (showSeconds()) {\n <div class=\"flex items-center justify-center gap-1 mt-2\">\n <span class=\"text-xs _shk-text-surface-400\">Seg:</span>\n <select\n class=\"px-2 py-1 text-xs _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md\"\n [value]=\"viewSecond()\"\n (change)=\"onSecondChange($event)\"\n aria-label=\"Segundos\"\n >\n @for (seconds of secondsRange(); track seconds) {\n <option [value]=\"seconds\">{{ minutesLabel(seconds) }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Confirm button -->\n <button\n type=\"button\"\n (click)=\"confirmTime()\"\n class=\"mt-3 w-full py-2 text-sm _shk-bg-primary _shk-text-white rounded-lg hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n {{ timeOnly() ? 'Confirmar' : 'Introducir hora' }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div [id]=\"id() + '-error'\" class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", styles: [".clock-container{position:relative;width:200px;height:200px;margin:0 auto}.clock-face{width:100%;height:100%;border-radius:50%;border:2px solid var(--shk-surface-200);position:relative;background-color:var(--shk-surface-50)}:host-context(.dark) .clock-face{border-color:var(--shk-surface-200);background-color:var(--shk-surface-100)}.clock-number{position:absolute;width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:500;border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:background-color .15s,color .15s;-webkit-user-select:none;user-select:none;color:var(--shk-surface-700)}:host-context(.dark) .clock-number{color:var(--shk-surface-700)}.clock-number:hover{background-color:var(--shk-surface-100)}:host-context(.dark) .clock-number:hover{background-color:var(--shk-surface-200)}.clock-number.selected{background-color:var(--shk-primary-500);color:#fff}.clock-number.current{font-weight:700}.clock-hand{position:absolute;bottom:50%;left:50%;width:2px;background-color:var(--shk-primary-500);transform-origin:bottom center;border-radius:1px;pointer-events:none;transition:transform .2s ease-out}.clock-center{position:absolute;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:var(--shk-primary-500);transform:translate(-50%,-50%);pointer-events:none;z-index:2}.clock-minute-marker{position:absolute;width:1px;height:8px;background-color:var(--shk-surface-300);top:6px;left:50%;transform-origin:center 94px}:host-context(.dark) .clock-minute-marker{background-color:var(--shk-surface-400)}.clock-minute-marker.major{width:2px;height:12px;background-color:var(--shk-surface-400)}:host-context(.dark) .clock-minute-marker.major{background-color:var(--shk-surface-500)}.clock-mode-toggle{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-top:.75rem}.clock-mode-btn{padding:.25rem .75rem;font-size:.75rem;font-weight:500;border-radius:9999px;cursor:pointer;transition:background-color .15s,color .15s;border:none;background:transparent;color:var(--shk-surface-500)}:host-context(.dark) .clock-mode-btn{color:var(--shk-surface-400)}.clock-mode-btn.active{background-color:var(--shk-primary-500);color:#fff}.clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-100)}:host-context(.dark) .clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-200)}.date-input-field{width:100%;padding:.5rem 2.5rem .5rem .75rem;font-size:.875rem;border-radius:.5rem;outline:none;transition:border-color .15s,box-shadow .15s;background-color:var(--shk-surface-50);color:var(--shk-surface-700);border:1px solid var(--shk-surface-200)}:host-context(.dark) .date-input-field{background-color:var(--shk-surface-100);color:var(--shk-surface-700);border-color:var(--shk-surface-200)}.date-input-field::placeholder{color:var(--shk-surface-400)}:host-context(.dark) .date-input-field::placeholder{color:var(--shk-surface-400)}.date-input-field:focus{border-color:var(--shk-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--shk-primary-500) 22%,transparent)}.date-input-field:disabled{background-color:var(--shk-surface-100);border-color:var(--shk-surface-200);color:var(--shk-surface-500);cursor:not-allowed}:host-context(.dark) .date-input-field:disabled{background-color:var(--shk-surface-50);color:var(--shk-surface-400)}.date-input-field.input-error{border-color:#ef4444}.date-input-field.input-error:focus{border-color:#ef4444;box-shadow:0 0 0 3px #ef444433}.date-input-field.input-valid{border-color:#22c55e}.date-input-field.input-valid:focus{border-color:#22c55e;box-shadow:0 0 0 3px #22c55e33}.date-input-field{text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
937
1018
|
}
|
|
938
1019
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
939
1020
|
type: Component,
|
|
@@ -943,8 +1024,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.23", ngImpo
|
|
|
943
1024
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
944
1025
|
multi: true,
|
|
945
1026
|
},
|
|
946
|
-
], template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n <div class=\"relative\">\n <input\n [id]=\"id()\"\n type=\"text\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isTyping() ? typedValue() : displayLabel()\"\n (input)=\"onInputText($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$any($event.target).blur()\"\n (keydown.escape)=\"cancelTyping()\"\n (click)=\"toggle()\"\n class=\"date-input-field\"\n [ngClass]=\"{\n 'input-error': shouldShowError() || typingValid() === false,\n 'input-valid': wasFixedError() || typingValid() === true,\n }\"\n [attr.aria-invalid]=\"shouldShowError()\"\n [attr.aria-describedby]=\"shouldShowError() ? id() + '-error' : null\"\n />\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n class=\"w-4 h-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n </div>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <!-- DATE VIEW -->\n @if (!timeOnly() && currentView() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n <!-- MONTH VIEW -->\n @if (!timeOnly() && currentView() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedMonthValue() === $index,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && selectedMonthValue() !== $index,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedMonthValue() !== $index && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n <!-- YEAR VIEW -->\n @if (!timeOnly() && currentView() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedYearValue() === year,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && selectedYearValue() !== year,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedYearValue() !== year && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n\n <!-- ANALOG CLOCK TIME PICKER -->\n @if (timeOnly() || showTime()) {\n <div class=\"mt-3 pt-3 _shk-border dark:[border-color:var(--shk-surface-200)]\">\n <!-- Clock display time -->\n <div class=\"text-center mb-2\">\n <span class=\"text-lg font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ clockDisplayTime() }}\n </span>\n </div>\n\n <!-- Analog clock face -->\n <div class=\"clock-container\">\n <svg\n viewBox=\"0 0 200 200\"\n class=\"w-full h-full cursor-pointer\"\n (click)=\"onClockClick($event, clockMode())\"\n >\n <!-- Clock face background -->\n <circle cx=\"100\" cy=\"100\" r=\"96\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\"\n class=\"_shk-text-surface-200 dark:[color:var(--shk-surface-200)]\" />\n\n <!-- Minute markers -->\n @if (clockMode() === 'minutes') {\n @for (i of [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59]; track i) {\n <line\n [attr.x1]=\"clockMinuteMarker(i).x1\"\n [attr.y1]=\"clockMinuteMarker(i).y1\"\n [attr.x2]=\"clockMinuteMarker(i).x2\"\n [attr.y2]=\"clockMinuteMarker(i).y2\"\n [attr.stroke-width]=\"i % 5 === 0 ? 2 : 1\"\n [class]=\"i % 5 === 0 ? '_shk-text-surface-500 dark:[color:var(--shk-surface-500)]' : '_shk-text-surface-300 dark:[color:var(--shk-surface-400)]'\"\n stroke=\"currentColor\"\n />\n }\n <!-- Minute numbers (00, 05, 10, ...) -->\n @for (m of [0,5,10,15,20,25,30,35,40,45,50,55]; track m) {\n <text\n [attr.x]=\"clockMinutePos(m).x\"\n [attr.y]=\"clockMinutePos(m).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-[9px] _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\"\n [class._shk-text-primary]=\"viewMinute() === m\"\n >\n {{ m.toString().padStart(2, '0') }}\n </text>\n }\n }\n\n <!-- Hour numbers -->\n @if (clockMode() === 'hours') {\n @for (h of clockHours(); track h) {\n <text\n [attr.x]=\"clockNumberPos(h).x\"\n [attr.y]=\"clockNumberPos(h).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-sm font-medium\"\n [class._shk-text-primary]=\"isClockHourSelected(h)\"\n [class._shk-text-surface-700]=\"!isClockHourSelected(h)\"\n >\n {{ h }}\n </text>\n }\n }\n\n <!-- Clock hand -->\n <line\n x1=\"100\" y1=\"100\"\n [attr.x2]=\"clockHandLine(60).x2\"\n [attr.y2]=\"clockHandLine(60).y2\"\n class=\"_shk-text-primary\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n\n <!-- Center dot -->\n <circle cx=\"100\" cy=\"100\" r=\"4\" class=\"fill-current _shk-text-primary\" />\n </svg>\n </div>\n\n <!-- Mode toggle: Hours / Minutes -->\n <div class=\"clock-mode-toggle\">\n <button\n type=\"button\"\n (click)=\"clockMode.set('hours')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'hours'\"\n >\n {{ 'Horas' }}\n </button>\n <button\n type=\"button\"\n (click)=\"clockMode.set('minutes')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'minutes'\"\n >\n {{ 'Minutos' }}\n </button>\n </div>\n\n <!-- AM/PM toggle for 12h format -->\n @if (hourFormat() === '12') {\n <div class=\"flex items-center justify-center gap-2 mt-2\">\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('AM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'AM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'AM'\n }\"\n >\n AM\n </button>\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('PM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'PM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'PM'\n }\"\n >\n PM\n </button>\n </div>\n }\n\n <!-- Seconds selector (if enabled) -->\n @if (showSeconds()) {\n <div class=\"flex items-center justify-center gap-1 mt-2\">\n <span class=\"text-xs _shk-text-surface-400\">Seg:</span>\n <select\n class=\"px-2 py-1 text-xs _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md\"\n [value]=\"viewSecond()\"\n (change)=\"onSecondChange($event)\"\n aria-label=\"Segundos\"\n >\n @for (seconds of secondsRange(); track seconds) {\n <option [value]=\"seconds\">{{ minutesLabel(seconds) }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Confirm button -->\n <button\n type=\"button\"\n (click)=\"confirmTime()\"\n class=\"mt-3 w-full py-2 text-sm _shk-bg-primary _shk-text-white rounded-lg hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n {{ timeOnly() ? 'Confirmar' : 'Introducir hora' }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div [id]=\"id() + '-error'\" class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", styles: [".clock-container{position:relative;width:200px;height:200px;margin:0 auto}.clock-face{width:100%;height:100%;border-radius:50%;border:2px solid var(--shk-surface-200);position:relative;background-color:var(--shk-surface-50)}.dark .clock-face{border-color:var(--shk-surface-200);background-color:var(--shk-surface-100)}.clock-number{position:absolute;width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:500;border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:background-color .15s,color .15s;-webkit-user-select:none;user-select:none;color:var(--shk-surface-700)}.dark .clock-number{color:var(--shk-surface-700)}.clock-number:hover{background-color:var(--shk-surface-100)}.dark .clock-number:hover{background-color:var(--shk-surface-200)}.clock-number.selected{background-color:var(--shk-primary-500);color:#fff}.clock-number.current{font-weight:700}.clock-hand{position:absolute;bottom:50%;left:50%;width:2px;background-color:var(--shk-primary-500);transform-origin:bottom center;border-radius:1px;pointer-events:none;transition:transform .2s ease-out}.clock-center{position:absolute;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:var(--shk-primary-500);transform:translate(-50%,-50%);pointer-events:none;z-index:2}.clock-minute-marker{position:absolute;width:1px;height:8px;background-color:var(--shk-surface-300);top:6px;left:50%;transform-origin:center 94px}.dark .clock-minute-marker{background-color:var(--shk-surface-400)}.clock-minute-marker.major{width:2px;height:12px;background-color:var(--shk-surface-400)}.dark .clock-minute-marker.major{background-color:var(--shk-surface-500)}.clock-mode-toggle{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-top:.75rem}.clock-mode-btn{padding:.25rem .75rem;font-size:.75rem;font-weight:500;border-radius:9999px;cursor:pointer;transition:background-color .15s,color .15s;border:none;background:transparent;color:var(--shk-surface-500)}.dark .clock-mode-btn{color:var(--shk-surface-400)}.clock-mode-btn.active{background-color:var(--shk-primary-500);color:#fff}.clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-100)}.dark .clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-200)}.date-input-field{width:100%;padding:.5rem 2.5rem .5rem .75rem;font-size:.875rem;border-radius:.5rem;outline:none;transition:border-color .15s,box-shadow .15s;background-color:var(--shk-surface-50);color:var(--shk-surface-700);border:1px solid var(--shk-surface-200)}.dark .date-input-field{background-color:var(--shk-surface-100);color:var(--shk-surface-700);border-color:var(--shk-surface-200)}.date-input-field::placeholder{color:var(--shk-surface-400)}.dark .date-input-field::placeholder{color:var(--shk-surface-400)}.date-input-field:focus{border-color:var(--shk-primary-500);box-shadow:0 0 0 1px var(--shk-primary-500)}.date-input-field:disabled{opacity:.5;cursor:not-allowed}.date-input-field.input-error{border-color:#ef4444}.date-input-field.input-error:focus{border-color:#ef4444;box-shadow:0 0 0 1px #ef4444}.date-input-field.input-valid{border-color:#22c55e}.date-input-field.input-valid:focus{border-color:#22c55e;box-shadow:0 0 0 1px #22c55e}\n"] }]
|
|
947
|
-
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], timeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeOnly", required: false }] }], showTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTime", required: false }] }], hourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], onDocumentClick: [{
|
|
1027
|
+
], template: "<div class=\"relative mb-4\">\n @if (label()) {\n <div class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)] mb-1\">\n {{ label() }}\n </div>\n }\n\n <div class=\"relative\">\n <div class=\"relative\">\n <input\n [id]=\"id()\"\n type=\"text\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isTyping() ? typedValue() : displayLabel()\"\n (input)=\"onInputText($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown.enter)=\"$any($event.target).blur()\"\n (keydown.escape)=\"cancelTyping()\"\n (click)=\"toggle()\"\n class=\"date-input-field\"\n [ngClass]=\"{\n 'input-error': shouldShowError() || typingValid() === false,\n 'input-valid': wasFixedError() || typingValid() === true,\n }\"\n [attr.aria-invalid]=\"shouldShowError()\"\n [attr.aria-describedby]=\"shouldShowError() ? id() + '-error' : null\"\n />\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n (click)=\"toggle()\"\n class=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 _shk-text-surface-400 dark:[color:var(--shk-surface-400)] hover:[color:var(--shk-surface-600)] dark:hover:[color:var(--shk-surface-300)] transition-colors\"\n >\n <svg\n class=\"w-4 h-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"></rect>\n <path d=\"M16 2v4M8 2v4M3 10h18\"></path>\n </svg>\n </button>\n </div>\n\n @if (isOpen()) {\n <div class=\"fixed inset-0 z-40 bg-black/30\" (click)=\"close()\"></div>\n <div\n class=\"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-72 p-4 bg-white dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-lg shadow-xl\"\n (click)=\"$event.stopPropagation()\"\n >\n <!-- DATE VIEW -->\n @if (!timeOnly() && currentView() === 'date') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-7 gap-0 mb-1\">\n @for (name of dayNames(); track $index) {\n <div class=\"text-center text-xs font-medium _shk-text-surface-400 dark:[color:var(--shk-surface-400)] py-1\">\n {{ name }}\n </div>\n }\n </div>\n\n <div class=\"grid grid-cols-7 gap-0\">\n @for (day of calendarDays(); track $index) {\n @if (day !== null) {\n <button\n type=\"button\"\n (click)=\"selectDay(day)\"\n class=\"py-1.5 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedDay(day),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isToday(day) && !isSelectedDay(day),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedDay(day) && !isToday(day),\n }\"\n >\n {{ day }}\n </button>\n } @else {\n <div></div>\n }\n }\n </div>\n }\n\n <!-- WEEK VIEW -->\n @if (!timeOnly() && currentView() === 'week') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ monthNames()[viewMonth()] }} {{ viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"space-y-1\">\n @for (week of monthWeeks(); track week.index) {\n <button\n type=\"button\"\n (click)=\"selectWeek(week.start)\"\n class=\"w-full flex items-center justify-between py-1.5 px-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': isSelectedWeek(week.start),\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentWeek(week.start) && !isSelectedWeek(week.start),\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': !isSelectedWeek(week.start) && !isCurrentWeek(week.start),\n }\"\n >\n <span class=\"font-medium\">{{ weekLabel(week.index) }}</span>\n <span class=\"text-xs opacity-80\">{{ week.range }}</span>\n </button>\n }\n </div>\n }\n\n <!-- MONTH VIEW -->\n @if (!timeOnly() && currentView() === 'month') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"drillUp()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ selectedYearValue() ?? viewYear() }}\n </span>\n <button\n type=\"button\"\n (click)=\"drillToInitial()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (name of monthNames(); track $index) {\n <button\n type=\"button\"\n (click)=\"selectMonth($index)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedMonthValue() === $index,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentMonth($index) && selectedMonthValue() !== $index,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedMonthValue() !== $index && !isCurrentMonth($index),\n }\"\n >\n {{ name }}\n </button>\n }\n </div>\n }\n\n <!-- YEAR VIEW -->\n @if (!timeOnly() && currentView() === 'year') {\n <div class=\"flex items-center justify-between mb-3\">\n <button\n type=\"button\"\n (click)=\"prev()\"\n [disabled]=\"!canGoPrev()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M15 18l-6-6 6-6\"></path>\n </svg>\n </button>\n <span class=\"text-sm font-medium _shk-text-surface-700 dark:[color:var(--shk-surface-600)]\">\n {{ viewDecade() }} - {{ viewDecade() + 11 }}\n </span>\n <button\n type=\"button\"\n (click)=\"next()\"\n [disabled]=\"!canGoNext()\"\n class=\"p-1 rounded hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] disabled:opacity-30 disabled:cursor-not-allowed\"\n >\n <svg class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M9 18l6-6-6-6\"></path>\n </svg>\n </button>\n </div>\n\n <div class=\"grid grid-cols-3 gap-1\">\n @for (year of decadeYears(); track year) {\n <button\n type=\"button\"\n (click)=\"selectYear(year)\"\n class=\"py-2 text-sm rounded transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white hover:[background-color:var(--shk-primary-700)]': selectedYearValue() === year,\n 'ring-1 [--tw-ring-color:var(--shk-primary-500)] _shk-text-surface-700 dark:[color:var(--shk-surface-700)]': isCurrentYear(year) && selectedYearValue() !== year,\n '_shk-text-surface-700 dark:[color:var(--shk-surface-700)] hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': selectedYearValue() !== year && !isCurrentYear(year),\n }\"\n >\n {{ year }}\n </button>\n }\n </div>\n }\n\n <!-- ANALOG CLOCK TIME PICKER -->\n @if (timeOnly() || showTime()) {\n <div class=\"mt-3 pt-3 _shk-border dark:[border-color:var(--shk-surface-200)]\">\n <!-- Clock display time -->\n <div class=\"text-center mb-2\">\n <span class=\"text-lg font-semibold _shk-text-surface-700 dark:[color:var(--shk-surface-700)]\">\n {{ clockDisplayTime() }}\n </span>\n </div>\n\n <!-- Analog clock face -->\n <div class=\"clock-container\">\n <svg\n viewBox=\"0 0 200 200\"\n class=\"w-full h-full cursor-pointer\"\n (click)=\"onClockClick($event, clockMode())\"\n >\n <!-- Clock face background -->\n <circle cx=\"100\" cy=\"100\" r=\"96\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\"\n class=\"_shk-text-surface-200 dark:[color:var(--shk-surface-200)]\" />\n\n <!-- Minute markers -->\n @if (clockMode() === 'minutes') {\n @for (i of [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59]; track i) {\n <line\n [attr.x1]=\"clockMinuteMarker(i).x1\"\n [attr.y1]=\"clockMinuteMarker(i).y1\"\n [attr.x2]=\"clockMinuteMarker(i).x2\"\n [attr.y2]=\"clockMinuteMarker(i).y2\"\n [attr.stroke-width]=\"i % 5 === 0 ? 2 : 1\"\n [class]=\"i % 5 === 0 ? '_shk-text-surface-500 dark:[color:var(--shk-surface-500)]' : '_shk-text-surface-300 dark:[color:var(--shk-surface-400)]'\"\n stroke=\"currentColor\"\n />\n }\n <!-- Minute numbers (00, 05, 10, ...) -->\n @for (m of [0,5,10,15,20,25,30,35,40,45,50,55]; track m) {\n <text\n [attr.x]=\"clockMinutePos(m).x\"\n [attr.y]=\"clockMinutePos(m).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-[9px] _shk-text-surface-500 dark:[color:var(--shk-surface-400)]\"\n [class._shk-text-primary]=\"viewMinute() === m\"\n >\n {{ m.toString().padStart(2, '0') }}\n </text>\n }\n }\n\n <!-- Hour numbers -->\n @if (clockMode() === 'hours') {\n @for (h of clockHours(); track h) {\n <text\n [attr.x]=\"clockNumberPos(h).x\"\n [attr.y]=\"clockNumberPos(h).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"central\"\n class=\"text-sm font-medium\"\n [class._shk-text-primary]=\"isClockHourSelected(h)\"\n [class._shk-text-surface-700]=\"!isClockHourSelected(h)\"\n >\n {{ h }}\n </text>\n }\n }\n\n <!-- Clock hand -->\n <line\n x1=\"100\" y1=\"100\"\n [attr.x2]=\"clockHandLine(60).x2\"\n [attr.y2]=\"clockHandLine(60).y2\"\n class=\"_shk-text-primary\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n\n <!-- Center dot -->\n <circle cx=\"100\" cy=\"100\" r=\"4\" class=\"fill-current _shk-text-primary\" />\n </svg>\n </div>\n\n <!-- Mode toggle: Hours / Minutes -->\n <div class=\"clock-mode-toggle\">\n <button\n type=\"button\"\n (click)=\"clockMode.set('hours')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'hours'\"\n >\n {{ 'Horas' }}\n </button>\n <button\n type=\"button\"\n (click)=\"clockMode.set('minutes')\"\n class=\"clock-mode-btn\"\n [class.active]=\"clockMode() === 'minutes'\"\n >\n {{ 'Minutos' }}\n </button>\n </div>\n\n <!-- AM/PM toggle for 12h format -->\n @if (hourFormat() === '12') {\n <div class=\"flex items-center justify-center gap-2 mt-2\">\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('AM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'AM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'AM'\n }\"\n >\n AM\n </button>\n <button\n type=\"button\"\n (click)=\"viewMeridiem.set('PM')\"\n class=\"px-3 py-1 text-xs font-medium rounded-full transition-colors\"\n [ngClass]=\"{\n '_shk-bg-primary _shk-text-white': viewMeridiem() === 'PM',\n '_shk-text-surface-500 hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)]': viewMeridiem() !== 'PM'\n }\"\n >\n PM\n </button>\n </div>\n }\n\n <!-- Seconds selector (if enabled) -->\n @if (showSeconds()) {\n <div class=\"flex items-center justify-center gap-1 mt-2\">\n <span class=\"text-xs _shk-text-surface-400\">Seg:</span>\n <select\n class=\"px-2 py-1 text-xs _shk-bg-surface-50 dark:[background-color:var(--shk-surface-100)] _shk-border dark:[border-color:var(--shk-surface-200)] rounded-md\"\n [value]=\"viewSecond()\"\n (change)=\"onSecondChange($event)\"\n aria-label=\"Segundos\"\n >\n @for (seconds of secondsRange(); track seconds) {\n <option [value]=\"seconds\">{{ minutesLabel(seconds) }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Confirm button -->\n <button\n type=\"button\"\n (click)=\"confirmTime()\"\n class=\"mt-3 w-full py-2 text-sm _shk-bg-primary _shk-text-white rounded-lg hover:[background-color:var(--shk-primary-700)] transition-colors\"\n >\n {{ timeOnly() ? 'Confirmar' : 'Introducir hora' }}\n </button>\n </div>\n }\n </div>\n }\n </div>\n\n @if (shouldShowError()) {\n <div [id]=\"id() + '-error'\" class=\"mt-1 text-xs text-red-500 max-h-20 overflow-y-auto _shk-scrollbar\">\n <ul class=\"list-disc pl-4 space-y-1\">\n @for (error of getErrorMessages(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </div>\n }\n</div>\n", styles: [".clock-container{position:relative;width:200px;height:200px;margin:0 auto}.clock-face{width:100%;height:100%;border-radius:50%;border:2px solid var(--shk-surface-200);position:relative;background-color:var(--shk-surface-50)}:host-context(.dark) .clock-face{border-color:var(--shk-surface-200);background-color:var(--shk-surface-100)}.clock-number{position:absolute;width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:500;border-radius:50%;transform:translate(-50%,-50%);cursor:pointer;transition:background-color .15s,color .15s;-webkit-user-select:none;user-select:none;color:var(--shk-surface-700)}:host-context(.dark) .clock-number{color:var(--shk-surface-700)}.clock-number:hover{background-color:var(--shk-surface-100)}:host-context(.dark) .clock-number:hover{background-color:var(--shk-surface-200)}.clock-number.selected{background-color:var(--shk-primary-500);color:#fff}.clock-number.current{font-weight:700}.clock-hand{position:absolute;bottom:50%;left:50%;width:2px;background-color:var(--shk-primary-500);transform-origin:bottom center;border-radius:1px;pointer-events:none;transition:transform .2s ease-out}.clock-center{position:absolute;top:50%;left:50%;width:8px;height:8px;border-radius:50%;background-color:var(--shk-primary-500);transform:translate(-50%,-50%);pointer-events:none;z-index:2}.clock-minute-marker{position:absolute;width:1px;height:8px;background-color:var(--shk-surface-300);top:6px;left:50%;transform-origin:center 94px}:host-context(.dark) .clock-minute-marker{background-color:var(--shk-surface-400)}.clock-minute-marker.major{width:2px;height:12px;background-color:var(--shk-surface-400)}:host-context(.dark) .clock-minute-marker.major{background-color:var(--shk-surface-500)}.clock-mode-toggle{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-top:.75rem}.clock-mode-btn{padding:.25rem .75rem;font-size:.75rem;font-weight:500;border-radius:9999px;cursor:pointer;transition:background-color .15s,color .15s;border:none;background:transparent;color:var(--shk-surface-500)}:host-context(.dark) .clock-mode-btn{color:var(--shk-surface-400)}.clock-mode-btn.active{background-color:var(--shk-primary-500);color:#fff}.clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-100)}:host-context(.dark) .clock-mode-btn:hover:not(.active){background-color:var(--shk-surface-200)}.date-input-field{width:100%;padding:.5rem 2.5rem .5rem .75rem;font-size:.875rem;border-radius:.5rem;outline:none;transition:border-color .15s,box-shadow .15s;background-color:var(--shk-surface-50);color:var(--shk-surface-700);border:1px solid var(--shk-surface-200)}:host-context(.dark) .date-input-field{background-color:var(--shk-surface-100);color:var(--shk-surface-700);border-color:var(--shk-surface-200)}.date-input-field::placeholder{color:var(--shk-surface-400)}:host-context(.dark) .date-input-field::placeholder{color:var(--shk-surface-400)}.date-input-field:focus{border-color:var(--shk-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--shk-primary-500) 22%,transparent)}.date-input-field:disabled{background-color:var(--shk-surface-100);border-color:var(--shk-surface-200);color:var(--shk-surface-500);cursor:not-allowed}:host-context(.dark) .date-input-field:disabled{background-color:var(--shk-surface-50);color:var(--shk-surface-400)}.date-input-field.input-error{border-color:#ef4444}.date-input-field.input-error:focus{border-color:#ef4444;box-shadow:0 0 0 3px #ef444433}.date-input-field.input-valid{border-color:#22c55e}.date-input-field.input-valid:focus{border-color:#22c55e;box-shadow:0 0 0 3px #22c55e33}.date-input-field{text-overflow:ellipsis}\n"] }]
|
|
1028
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }], weekStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStart", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], timeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeOnly", required: false }] }], showTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTime", required: false }] }], hourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], onDocumentClick: [{
|
|
948
1029
|
type: HostListener,
|
|
949
1030
|
args: ['document:click', ['$event']]
|
|
950
1031
|
}], onEscape: [{
|