@cocoar/ui-components 0.1.0-beta.122 → 0.1.0-beta.126
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.
|
@@ -643,7 +643,9 @@ function transformStepperButtons(value) {
|
|
|
643
643
|
class CoarNumberInputComponent extends CoarControlValueAccessor {
|
|
644
644
|
destroyRef = inject(DestroyRef);
|
|
645
645
|
localizationService = inject(CoarLocalizationService, { optional: true });
|
|
646
|
-
currentLanguage = toSignal(this.localizationService?.
|
|
646
|
+
currentLanguage = toSignal(this.localizationService?.languageState.value$ ?? of(navigator.language), {
|
|
647
|
+
initialValue: this.localizationService?.languageState.value ?? navigator.language,
|
|
648
|
+
});
|
|
647
649
|
maskitoInstance;
|
|
648
650
|
/** Label text displayed above the input */
|
|
649
651
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
@@ -841,9 +843,7 @@ class CoarNumberInputComponent extends CoarControlValueAccessor {
|
|
|
841
843
|
return null;
|
|
842
844
|
const format = this.resolveNumberFormat();
|
|
843
845
|
// Remove thousand separators first (before converting decimal)
|
|
844
|
-
const withoutThousands = format.thousand
|
|
845
|
-
? str.replace(new RegExp(`\\${format.thousand}`, 'g'), '')
|
|
846
|
-
: str;
|
|
846
|
+
const withoutThousands = format.thousand ? str.replace(new RegExp(`\\${format.thousand}`, 'g'), '') : str;
|
|
847
847
|
// Replace locale-specific decimal separator with period for parseFloat
|
|
848
848
|
const normalized = withoutThousands.replace(format.decimal, '.');
|
|
849
849
|
const parsed = parseFloat(normalized);
|
|
@@ -3990,22 +3990,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
3990
3990
|
}, styles: [":host{display:block}.coar-table-wrapper{overflow-x:auto;border:1px solid var(--coar-border-neutral-tertiary);border-radius:var(--coar-radius-xs);background:var(--coar-background-neutral-primary)}.coar-table{width:100%;border-collapse:collapse;font-family:var(--coar-body-base-family);font-size:.875rem;line-height:1.5}.coar-table ::ng-deep thead{background:var(--coar-background-neutral-secondary)}.coar-table ::ng-deep th{padding:.75rem 1rem;text-align:left;font-weight:600;font-size:.8125rem;color:var(--coar-text-neutral-primary);border-bottom:1px solid var(--coar-border-neutral-tertiary);white-space:nowrap;text-transform:uppercase;letter-spacing:.025em}.coar-table ::ng-deep tbody tr:nth-child(odd){background:var(--coar-background-neutral-primary)}.coar-table ::ng-deep tbody tr:nth-child(2n){background:var(--coar-background-neutral-secondary)}.coar-table ::ng-deep td{padding:.75rem 1rem;text-align:left;color:var(--coar-text-neutral-secondary);vertical-align:top}.coar-table ::ng-deep code{font-family:Consolas,Monaco,Courier New,monospace;font-size:.8125rem;color:var(--coar-text-accent-secondary);white-space:nowrap}:host(.coar-table--plain) .coar-table ::ng-deep tbody tr:nth-child(odd),:host(.coar-table--plain) .coar-table ::ng-deep tbody tr:nth-child(2n){background:var(--coar-background-neutral-primary)}:host(.coar-table--plain) .coar-table ::ng-deep td{border-bottom:1px solid var(--coar-border-neutral-tertiary)}:host(.coar-table--plain) .coar-table ::ng-deep tbody tr:last-child td{border-bottom:none}:host(.coar-table--bordered) .coar-table-wrapper{border:none}:host(.coar-table--bordered) .coar-table ::ng-deep th,:host(.coar-table--bordered) .coar-table ::ng-deep td{border:1px solid var(--coar-border-neutral-tertiary)}:host(.coar-table--bordered) .coar-table ::ng-deep tbody tr:nth-child(odd),:host(.coar-table--bordered) .coar-table ::ng-deep tbody tr:nth-child(2n){background:var(--coar-background-neutral-primary)}:host(.coar-table--compact) .coar-table ::ng-deep th,:host(.coar-table--compact) .coar-table ::ng-deep td{padding:.5rem .75rem;font-size:.8125rem}:host(.coar-table--hover) .coar-table ::ng-deep tbody tr:hover{background:var(--coar-background-neutral-secondary)}.coar-table ::ng-deep .text-right{text-align:right}.coar-table ::ng-deep .text-center{text-align:center}.coar-table ::ng-deep .nowrap{white-space:nowrap}.coar-table ::ng-deep .prop-name code{color:var(--coar-text-accent-primary);font-weight:500}.coar-table ::ng-deep .type{color:var(--coar-text-neutral-tertiary)}.coar-table ::ng-deep .default{color:var(--coar-text-neutral-tertiary)}.coar-table ::ng-deep .required-badge{display:inline-block;margin-left:.5rem;padding:.125rem .375rem;font-size:.625rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--coar-text-semantic-warning-bold);background:var(--coar-background-semantic-warning-subtle);border-radius:var(--coar-radius-xxs);vertical-align:middle}\n"] }]
|
|
3991
3991
|
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], hover: [{ type: i0.Input, args: [{ isSignal: true, alias: "hover", required: false }] }] } });
|
|
3992
3992
|
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3993
|
+
function coarDetectDateFormatPatternFromIntl(locale) {
|
|
3994
|
+
try {
|
|
3995
|
+
const formatter = new Intl.DateTimeFormat(locale);
|
|
3996
|
+
const parts = formatter.formatToParts(new Date(2024, 0, 15));
|
|
3997
|
+
const dayIndex = parts.findIndex((p) => p.type === 'day');
|
|
3998
|
+
const monthIndex = parts.findIndex((p) => p.type === 'month');
|
|
3999
|
+
const yearIndex = parts.findIndex((p) => p.type === 'year');
|
|
4000
|
+
if (dayIndex === -1 || monthIndex === -1 || yearIndex === -1) {
|
|
4001
|
+
return null;
|
|
4002
|
+
}
|
|
4003
|
+
if (dayIndex < monthIndex && monthIndex < yearIndex)
|
|
4004
|
+
return 'dd.mm.yyyy';
|
|
4005
|
+
if (monthIndex < dayIndex && dayIndex < yearIndex)
|
|
4006
|
+
return 'mm/dd/yyyy';
|
|
4007
|
+
if (yearIndex < monthIndex && monthIndex < dayIndex)
|
|
4008
|
+
return 'yyyy-mm-dd';
|
|
4009
|
+
return null;
|
|
4010
|
+
}
|
|
4011
|
+
catch {
|
|
4012
|
+
return null;
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
function coarGetDateSeparatorForPattern(pattern) {
|
|
4016
|
+
if (pattern.includes('.'))
|
|
4017
|
+
return '.';
|
|
4018
|
+
if (pattern.includes('/'))
|
|
4019
|
+
return '/';
|
|
4020
|
+
return '-';
|
|
4021
|
+
}
|
|
4022
|
+
function coarGetLocalizedWeekdays(locale, firstDayOfWeek) {
|
|
3998
4023
|
const formatter = new Intl.DateTimeFormat(locale, { weekday: 'short' });
|
|
3999
|
-
// Jan 1, 2024 is a Monday - use this as reference for day mapping
|
|
4024
|
+
// Jan 1, 2024 is a Monday - use this as reference for day mapping.
|
|
4000
4025
|
const weekdays = [];
|
|
4001
4026
|
for (let i = 0; i < 7; i++) {
|
|
4002
|
-
// Start from Monday (Jan 1) and go through the week
|
|
4003
4027
|
const date = new Date(2024, 0, 1 + i);
|
|
4004
4028
|
weekdays.push(formatter.format(date));
|
|
4005
4029
|
}
|
|
4006
|
-
// weekdays is now [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
|
|
4030
|
+
// weekdays is now [Mon, Tue, Wed, Thu, Fri, Sat, Sun].
|
|
4007
4031
|
if (firstDayOfWeek === 7) {
|
|
4008
|
-
// Rotate to start with Sunday
|
|
4009
4032
|
const sunday = weekdays.pop();
|
|
4010
4033
|
if (sunday) {
|
|
4011
4034
|
weekdays.unshift(sunday);
|
|
@@ -4013,6 +4036,370 @@ function getLocalizedWeekdays(locale, firstDayOfWeek) {
|
|
|
4013
4036
|
}
|
|
4014
4037
|
return weekdays;
|
|
4015
4038
|
}
|
|
4039
|
+
function coarFormatPlainDate(date, pattern) {
|
|
4040
|
+
const sep = coarGetDateSeparatorForPattern(pattern);
|
|
4041
|
+
const day = String(date.day).padStart(2, '0');
|
|
4042
|
+
const month = String(date.month).padStart(2, '0');
|
|
4043
|
+
const year = String(date.year);
|
|
4044
|
+
switch (pattern) {
|
|
4045
|
+
case 'dd.mm.yyyy':
|
|
4046
|
+
case 'dd/mm/yyyy':
|
|
4047
|
+
return `${day}${sep}${month}${sep}${year}`;
|
|
4048
|
+
case 'mm/dd/yyyy':
|
|
4049
|
+
return `${month}${sep}${day}${sep}${year}`;
|
|
4050
|
+
case 'yyyy-mm-dd':
|
|
4051
|
+
return `${year}${sep}${month}${sep}${day}`;
|
|
4052
|
+
default:
|
|
4053
|
+
return `${day}${sep}${month}${sep}${year}`;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
function coarParsePlainDateFromInput(text, pattern, constraints) {
|
|
4057
|
+
if (!text)
|
|
4058
|
+
return null;
|
|
4059
|
+
const sep = coarGetDateSeparatorForPattern(pattern);
|
|
4060
|
+
const parts = text.split(sep);
|
|
4061
|
+
if (parts.length !== 3)
|
|
4062
|
+
return null;
|
|
4063
|
+
if (parts.some((p) => p.length === 0 || !/^\d+$/.test(p)))
|
|
4064
|
+
return null;
|
|
4065
|
+
let year;
|
|
4066
|
+
let month;
|
|
4067
|
+
let day;
|
|
4068
|
+
try {
|
|
4069
|
+
switch (pattern) {
|
|
4070
|
+
case 'dd.mm.yyyy':
|
|
4071
|
+
case 'dd/mm/yyyy':
|
|
4072
|
+
day = parseInt(parts[0], 10);
|
|
4073
|
+
month = parseInt(parts[1], 10);
|
|
4074
|
+
year = parseInt(parts[2], 10);
|
|
4075
|
+
break;
|
|
4076
|
+
case 'mm/dd/yyyy':
|
|
4077
|
+
month = parseInt(parts[0], 10);
|
|
4078
|
+
day = parseInt(parts[1], 10);
|
|
4079
|
+
year = parseInt(parts[2], 10);
|
|
4080
|
+
break;
|
|
4081
|
+
case 'yyyy-mm-dd':
|
|
4082
|
+
year = parseInt(parts[0], 10);
|
|
4083
|
+
month = parseInt(parts[1], 10);
|
|
4084
|
+
day = parseInt(parts[2], 10);
|
|
4085
|
+
break;
|
|
4086
|
+
default:
|
|
4087
|
+
return null;
|
|
4088
|
+
}
|
|
4089
|
+
if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31) {
|
|
4090
|
+
return null;
|
|
4091
|
+
}
|
|
4092
|
+
const date = Temporal.PlainDate.from({ year, month, day });
|
|
4093
|
+
const minDate = constraints?.min ?? null;
|
|
4094
|
+
const maxDate = constraints?.max ?? null;
|
|
4095
|
+
if (minDate && Temporal.PlainDate.compare(date, minDate) < 0) {
|
|
4096
|
+
return null;
|
|
4097
|
+
}
|
|
4098
|
+
if (maxDate && Temporal.PlainDate.compare(date, maxDate) > 0) {
|
|
4099
|
+
return null;
|
|
4100
|
+
}
|
|
4101
|
+
return date;
|
|
4102
|
+
}
|
|
4103
|
+
catch {
|
|
4104
|
+
return null;
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
function coarTemporalPlainDateToDate(date) {
|
|
4108
|
+
return new Date(date.year, date.month - 1, date.day);
|
|
4109
|
+
}
|
|
4110
|
+
function coarCalculateIsoWeekNumber(date) {
|
|
4111
|
+
const jsDate = coarTemporalPlainDateToDate(date);
|
|
4112
|
+
const dayOfWeek = jsDate.getDay() || 7;
|
|
4113
|
+
jsDate.setDate(jsDate.getDate() + 4 - dayOfWeek);
|
|
4114
|
+
const yearStart = new Date(jsDate.getFullYear(), 0, 1);
|
|
4115
|
+
return Math.ceil(((jsDate.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
|
|
4116
|
+
}
|
|
4117
|
+
function coarClampPlainDate(date, constraints) {
|
|
4118
|
+
const minDate = constraints?.min ?? null;
|
|
4119
|
+
const maxDate = constraints?.max ?? null;
|
|
4120
|
+
if (minDate && Temporal.PlainDate.compare(date, minDate) < 0) {
|
|
4121
|
+
return minDate;
|
|
4122
|
+
}
|
|
4123
|
+
if (maxDate && Temporal.PlainDate.compare(date, maxDate) > 0) {
|
|
4124
|
+
return maxDate;
|
|
4125
|
+
}
|
|
4126
|
+
return date;
|
|
4127
|
+
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Returns a fixed 6x7 calendar grid (42 cells) for the given month.
|
|
4130
|
+
* Includes leading/trailing days from adjacent months to fill the grid.
|
|
4131
|
+
*/
|
|
4132
|
+
function coarGetCalendarGridDates(viewMonth, firstDayOfWeek) {
|
|
4133
|
+
const firstDay = viewMonth.toPlainDate({ day: 1 });
|
|
4134
|
+
const daysInMonth = viewMonth.daysInMonth;
|
|
4135
|
+
const startDayOfWeek = firstDay.dayOfWeek; // Temporal: 1=Mon ... 7=Sun
|
|
4136
|
+
let daysFromPrevMonth;
|
|
4137
|
+
if (firstDayOfWeek === 1) {
|
|
4138
|
+
// Monday first: Monday=0, Tuesday=1, ..., Sunday=6
|
|
4139
|
+
daysFromPrevMonth = (startDayOfWeek - 1 + 7) % 7;
|
|
4140
|
+
}
|
|
4141
|
+
else {
|
|
4142
|
+
// Sunday first: Sunday=0, Monday=1, ..., Saturday=6
|
|
4143
|
+
// Temporal uses: Sunday=7, so we convert via modulo
|
|
4144
|
+
daysFromPrevMonth = startDayOfWeek % 7;
|
|
4145
|
+
}
|
|
4146
|
+
const cells = [];
|
|
4147
|
+
if (daysFromPrevMonth > 0) {
|
|
4148
|
+
const prevMonth = viewMonth.subtract({ months: 1 });
|
|
4149
|
+
const prevMonthDays = prevMonth.daysInMonth;
|
|
4150
|
+
for (let i = daysFromPrevMonth - 1; i >= 0; i--) {
|
|
4151
|
+
const day = prevMonth.toPlainDate({ day: prevMonthDays - i });
|
|
4152
|
+
cells.push({ date: day, isOutsideMonth: true });
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
for (let d = 1; d <= daysInMonth; d++) {
|
|
4156
|
+
const day = viewMonth.toPlainDate({ day: d });
|
|
4157
|
+
cells.push({ date: day, isOutsideMonth: false });
|
|
4158
|
+
}
|
|
4159
|
+
const remainingDays = 42 - cells.length;
|
|
4160
|
+
const nextMonth = viewMonth.add({ months: 1 });
|
|
4161
|
+
for (let d = 1; d <= remainingDays; d++) {
|
|
4162
|
+
const day = nextMonth.toPlainDate({ day: d });
|
|
4163
|
+
cells.push({ date: day, isOutsideMonth: true });
|
|
4164
|
+
}
|
|
4165
|
+
return cells;
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4168
|
+
class CoarMiniCalendarComponent {
|
|
4169
|
+
/** Current selected date (two-way bindable with [(value)]) */
|
|
4170
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
4171
|
+
valueChange = output();
|
|
4172
|
+
/** Minimum selectable date */
|
|
4173
|
+
min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
4174
|
+
/** Maximum selectable date */
|
|
4175
|
+
max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
4176
|
+
/** Locale identifier for calendar month/week labels */
|
|
4177
|
+
locale = input(navigator.language, ...(ngDevMode ? [{ debugName: "locale" }] : []));
|
|
4178
|
+
/** Date format configuration (pattern and first day of week) */
|
|
4179
|
+
dateFormatConfig = input(...(ngDevMode ? [undefined, { debugName: "dateFormatConfig" }] : []));
|
|
4180
|
+
/** Whether to show a "Today" button */
|
|
4181
|
+
showTodayButton = input(true, { ...(ngDevMode ? { debugName: "showTodayButton" } : {}), transform: booleanAttribute });
|
|
4182
|
+
/** Whether to show week numbers */
|
|
4183
|
+
showWeekNumbers = input(false, { ...(ngDevMode ? { debugName: "showWeekNumbers" } : {}), transform: booleanAttribute });
|
|
4184
|
+
/** Whether to highlight weekend days (Saturday/Sunday) with a subtle background */
|
|
4185
|
+
highlightWeekends = input(false, { ...(ngDevMode ? { debugName: "highlightWeekends" } : {}), transform: booleanAttribute });
|
|
4186
|
+
/** Date markers for highlighting special dates (holidays, events, etc.) */
|
|
4187
|
+
markers = input([], ...(ngDevMode ? [{ debugName: "markers" }] : []));
|
|
4188
|
+
/** Maximum number of lines shown in the marker popover (including "+N" line). */
|
|
4189
|
+
markerPopoverMaxLines = 5;
|
|
4190
|
+
/** Visible markers before switching to "+N other events". */
|
|
4191
|
+
markerPopoverVisibleMarkers = 4;
|
|
4192
|
+
today = Temporal.Now.plainDateISO();
|
|
4193
|
+
/** Currently viewed month/year in the calendar */
|
|
4194
|
+
viewDate = signal(this.today.toPlainYearMonth(), ...(ngDevMode ? [{ debugName: "viewDate" }] : []));
|
|
4195
|
+
/** Focused date in the calendar (for keyboard navigation) */
|
|
4196
|
+
focusedDate = signal(null, ...(ngDevMode ? [{ debugName: "focusedDate" }] : []));
|
|
4197
|
+
effectiveDateFormat = computed(() => {
|
|
4198
|
+
const directConfig = this.dateFormatConfig();
|
|
4199
|
+
if (directConfig)
|
|
4200
|
+
return directConfig;
|
|
4201
|
+
const detectedPattern = coarDetectDateFormatPatternFromIntl(this.locale());
|
|
4202
|
+
return { pattern: detectedPattern ?? 'dd.mm.yyyy', firstDayOfWeek: 1 };
|
|
4203
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
|
|
4204
|
+
firstDayOfWeek = computed(() => this.effectiveDateFormat().firstDayOfWeek, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
4205
|
+
daysOfWeek = computed(() => coarGetLocalizedWeekdays(this.locale(), this.firstDayOfWeek()), ...(ngDevMode ? [{ debugName: "daysOfWeek" }] : []));
|
|
4206
|
+
calendarDays = computed(() => {
|
|
4207
|
+
const viewMonth = this.viewDate();
|
|
4208
|
+
const grid = coarGetCalendarGridDates(viewMonth, this.firstDayOfWeek());
|
|
4209
|
+
return grid.map((cell) => this.createCalendarDay(cell.date, cell.isOutsideMonth));
|
|
4210
|
+
}, ...(ngDevMode ? [{ debugName: "calendarDays" }] : []));
|
|
4211
|
+
viewMonth = computed(() => {
|
|
4212
|
+
const viewMonth = this.viewDate();
|
|
4213
|
+
const formatter = new Intl.DateTimeFormat(this.locale(), { month: 'long' });
|
|
4214
|
+
const jsDate = new Date(viewMonth.year, viewMonth.month - 1, 1);
|
|
4215
|
+
return formatter.format(jsDate);
|
|
4216
|
+
}, ...(ngDevMode ? [{ debugName: "viewMonth" }] : []));
|
|
4217
|
+
viewYear = computed(() => this.viewDate().year, ...(ngDevMode ? [{ debugName: "viewYear" }] : []));
|
|
4218
|
+
weekNumbers = computed(() => {
|
|
4219
|
+
const days = this.calendarDays();
|
|
4220
|
+
const weeks = [];
|
|
4221
|
+
for (let i = 0; i < 6; i++) {
|
|
4222
|
+
const firstDayOfWeek = days[i * 7];
|
|
4223
|
+
if (firstDayOfWeek) {
|
|
4224
|
+
const weekNum = firstDayOfWeek.date.weekOfYear ?? coarCalculateIsoWeekNumber(firstDayOfWeek.date);
|
|
4225
|
+
weeks.push(weekNum);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
return weeks;
|
|
4229
|
+
}, ...(ngDevMode ? [{ debugName: "weekNumbers" }] : []));
|
|
4230
|
+
constructor() {
|
|
4231
|
+
// Keep the view month in sync when a value is provided/changed.
|
|
4232
|
+
effect(() => {
|
|
4233
|
+
const val = this.value();
|
|
4234
|
+
if (!val)
|
|
4235
|
+
return;
|
|
4236
|
+
this.viewDate.set(val.toPlainYearMonth());
|
|
4237
|
+
// Set a sensible default focus when a value arrives.
|
|
4238
|
+
if (!this.focusedDate()) {
|
|
4239
|
+
this.focusedDate.set(val);
|
|
4240
|
+
}
|
|
4241
|
+
});
|
|
4242
|
+
// Default focus when no value is set.
|
|
4243
|
+
effect(() => {
|
|
4244
|
+
if (this.value())
|
|
4245
|
+
return;
|
|
4246
|
+
if (this.focusedDate())
|
|
4247
|
+
return;
|
|
4248
|
+
this.focusedDate.set(this.today);
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
previousMonth() {
|
|
4252
|
+
this.viewDate.update((d) => d.subtract({ months: 1 }));
|
|
4253
|
+
}
|
|
4254
|
+
nextMonth() {
|
|
4255
|
+
this.viewDate.update((d) => d.add({ months: 1 }));
|
|
4256
|
+
}
|
|
4257
|
+
previousYear() {
|
|
4258
|
+
this.viewDate.update((d) => d.subtract({ years: 1 }));
|
|
4259
|
+
}
|
|
4260
|
+
nextYear() {
|
|
4261
|
+
this.viewDate.update((d) => d.add({ years: 1 }));
|
|
4262
|
+
}
|
|
4263
|
+
goToToday() {
|
|
4264
|
+
this.viewDate.set(this.today.toPlainYearMonth());
|
|
4265
|
+
this.focusedDate.set(this.today);
|
|
4266
|
+
}
|
|
4267
|
+
selectDate(date) {
|
|
4268
|
+
if (this.isDateDisabled(date))
|
|
4269
|
+
return;
|
|
4270
|
+
this.value.set(date);
|
|
4271
|
+
this.valueChange.emit(date);
|
|
4272
|
+
this.focusedDate.set(date);
|
|
4273
|
+
}
|
|
4274
|
+
onKeydown(event) {
|
|
4275
|
+
switch (event.key) {
|
|
4276
|
+
case 'Enter':
|
|
4277
|
+
case ' ': {
|
|
4278
|
+
event.preventDefault();
|
|
4279
|
+
const focused = this.focusedDate();
|
|
4280
|
+
if (focused) {
|
|
4281
|
+
this.selectDate(focused);
|
|
4282
|
+
}
|
|
4283
|
+
break;
|
|
4284
|
+
}
|
|
4285
|
+
case 'ArrowLeft':
|
|
4286
|
+
event.preventDefault();
|
|
4287
|
+
this.moveFocus(-1, 'day');
|
|
4288
|
+
break;
|
|
4289
|
+
case 'ArrowRight':
|
|
4290
|
+
event.preventDefault();
|
|
4291
|
+
this.moveFocus(1, 'day');
|
|
4292
|
+
break;
|
|
4293
|
+
case 'ArrowUp':
|
|
4294
|
+
event.preventDefault();
|
|
4295
|
+
this.moveFocus(-7, 'day');
|
|
4296
|
+
break;
|
|
4297
|
+
case 'ArrowDown':
|
|
4298
|
+
event.preventDefault();
|
|
4299
|
+
this.moveFocus(7, 'day');
|
|
4300
|
+
break;
|
|
4301
|
+
case 'PageUp':
|
|
4302
|
+
event.preventDefault();
|
|
4303
|
+
if (event.shiftKey) {
|
|
4304
|
+
this.moveFocus(-1, 'year');
|
|
4305
|
+
}
|
|
4306
|
+
else {
|
|
4307
|
+
this.moveFocus(-1, 'month');
|
|
4308
|
+
}
|
|
4309
|
+
break;
|
|
4310
|
+
case 'PageDown':
|
|
4311
|
+
event.preventDefault();
|
|
4312
|
+
if (event.shiftKey) {
|
|
4313
|
+
this.moveFocus(1, 'year');
|
|
4314
|
+
}
|
|
4315
|
+
else {
|
|
4316
|
+
this.moveFocus(1, 'month');
|
|
4317
|
+
}
|
|
4318
|
+
break;
|
|
4319
|
+
case 'Home':
|
|
4320
|
+
event.preventDefault();
|
|
4321
|
+
this.goToToday();
|
|
4322
|
+
break;
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
getVisibleMarkers(markers) {
|
|
4326
|
+
if (markers.length <= this.markerPopoverMaxLines) {
|
|
4327
|
+
return markers;
|
|
4328
|
+
}
|
|
4329
|
+
return markers.slice(0, this.markerPopoverVisibleMarkers);
|
|
4330
|
+
}
|
|
4331
|
+
getHiddenMarkerCount(markers) {
|
|
4332
|
+
if (markers.length <= this.markerPopoverMaxLines) {
|
|
4333
|
+
return 0;
|
|
4334
|
+
}
|
|
4335
|
+
return Math.max(0, markers.length - this.markerPopoverVisibleMarkers);
|
|
4336
|
+
}
|
|
4337
|
+
getMarkersForDate(date) {
|
|
4338
|
+
const markers = this.markers();
|
|
4339
|
+
const matches = [];
|
|
4340
|
+
for (const marker of markers) {
|
|
4341
|
+
const start = marker.startDate;
|
|
4342
|
+
const end = marker.endDate ?? marker.startDate;
|
|
4343
|
+
if (Temporal.PlainDate.compare(date, start) >= 0 &&
|
|
4344
|
+
Temporal.PlainDate.compare(date, end) <= 0) {
|
|
4345
|
+
matches.push(marker);
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
return matches;
|
|
4349
|
+
}
|
|
4350
|
+
isDateDisabled(date) {
|
|
4351
|
+
const minDate = this.min();
|
|
4352
|
+
const maxDate = this.max();
|
|
4353
|
+
if (minDate && Temporal.PlainDate.compare(date, minDate) < 0)
|
|
4354
|
+
return true;
|
|
4355
|
+
if (maxDate && Temporal.PlainDate.compare(date, maxDate) > 0)
|
|
4356
|
+
return true;
|
|
4357
|
+
return false;
|
|
4358
|
+
}
|
|
4359
|
+
moveFocus(amount, unit) {
|
|
4360
|
+
const current = this.focusedDate() ?? this.value() ?? this.today;
|
|
4361
|
+
let newDate;
|
|
4362
|
+
switch (unit) {
|
|
4363
|
+
case 'day':
|
|
4364
|
+
newDate = current.add({ days: amount });
|
|
4365
|
+
break;
|
|
4366
|
+
case 'month':
|
|
4367
|
+
newDate = current.add({ months: amount });
|
|
4368
|
+
break;
|
|
4369
|
+
case 'year':
|
|
4370
|
+
newDate = current.add({ years: amount });
|
|
4371
|
+
break;
|
|
4372
|
+
}
|
|
4373
|
+
newDate = coarClampPlainDate(newDate, { min: this.min(), max: this.max() });
|
|
4374
|
+
this.focusedDate.set(newDate);
|
|
4375
|
+
this.viewDate.set(newDate.toPlainYearMonth());
|
|
4376
|
+
}
|
|
4377
|
+
createCalendarDay(date, isOutsideMonth) {
|
|
4378
|
+
const selected = this.value();
|
|
4379
|
+
const focused = this.focusedDate();
|
|
4380
|
+
const dayOfWeek = date.dayOfWeek;
|
|
4381
|
+
const markers = this.getMarkersForDate(date);
|
|
4382
|
+
return {
|
|
4383
|
+
date,
|
|
4384
|
+
day: date.day,
|
|
4385
|
+
isOutsideMonth,
|
|
4386
|
+
isToday: Temporal.PlainDate.compare(date, this.today) === 0,
|
|
4387
|
+
isSelected: selected ? Temporal.PlainDate.compare(date, selected) === 0 : false,
|
|
4388
|
+
isFocused: focused ? Temporal.PlainDate.compare(date, focused) === 0 : false,
|
|
4389
|
+
isDisabled: this.isDateDisabled(date),
|
|
4390
|
+
isWeekend: dayOfWeek === 6 || dayOfWeek === 7,
|
|
4391
|
+
markers,
|
|
4392
|
+
markerCssClass: markers[0]?.cssClass ?? null,
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarMiniCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4396
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CoarMiniCalendarComponent, isStandalone: true, selector: "coar-mini-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormatConfig: { classPropertyName: "dateFormatConfig", publicName: "dateFormatConfig", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, highlightWeekends: { classPropertyName: "highlightWeekends", publicName: "highlightWeekends", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange" }, providers: [CoarPopoverGroupService], ngImport: i0, template: "<div class=\"coar-mini-calendar\" role=\"application\" (keydown)=\"onKeydown($event)\">\n <div class=\"coar-mini-calendar-header\">\n <button type=\"button\" class=\"coar-mini-calendar-nav\" aria-label=\"Previous year\" (click)=\"previousYear()\">\n <coar-icon name=\"chevrons-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-mini-calendar-nav\" aria-label=\"Previous month\" (click)=\"previousMonth()\">\n <coar-icon name=\"chevron-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n\n <span class=\"coar-mini-calendar-month-year\">\n <span class=\"coar-mini-calendar-month\">{{ viewMonth() }}</span>\n <span class=\"coar-mini-calendar-year\">{{ viewYear() }}</span>\n </span>\n\n <button type=\"button\" class=\"coar-mini-calendar-nav coar-mini-calendar-nav--next\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <coar-icon name=\"chevron-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-mini-calendar-nav coar-mini-calendar-nav--next\" aria-label=\"Next year\" (click)=\"nextYear()\">\n <coar-icon name=\"chevrons-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <div class=\"coar-mini-calendar-weekdays\" [class.coar-mini-calendar-weekdays--with-weeks]=\"showWeekNumbers()\">\n @if (showWeekNumbers()) {\n <span class=\"coar-mini-calendar-week-spacer\"></span>\n }\n @for (day of daysOfWeek(); track day) {\n <span class=\"coar-mini-calendar-weekday\">{{ day }}</span>\n }\n </div>\n\n <div class=\"coar-mini-calendar-grid\" [class.coar-mini-calendar-grid--with-weeks]=\"showWeekNumbers()\" role=\"grid\">\n @for (day of calendarDays(); track day.date.toString(); let i = $index) {\n @if (showWeekNumbers() && i % 7 === 0) {\n <span class=\"coar-mini-calendar-week-number\">{{ weekNumbers()[i / 7] }}</span>\n }\n\n <coar-popover [disabled]=\"day.isDisabled || day.markers.length === 0\" [openOnClick]=\"true\" [openOnHover]=\"true\" [interactive]=\"false\">\n <button\n coarPopoverTrigger\n type=\"button\"\n class=\"coar-mini-calendar-day\"\n [class.coar-mini-calendar-day--outside]=\"day.isOutsideMonth\"\n [class.coar-mini-calendar-day--today]=\"day.isToday\"\n [class.coar-mini-calendar-day--selected]=\"day.isSelected\"\n [class.coar-mini-calendar-day--focused]=\"day.isFocused\"\n [class.coar-mini-calendar-day--disabled]=\"day.isDisabled\"\n [class.coar-mini-calendar-day--weekend]=\"highlightWeekends() && day.isWeekend\"\n [class.coar-mini-calendar-day--marked]=\"day.markers.length > 0\"\n [class]=\"day.markerCssClass\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDate(day.date)\"\n >\n {{ day.day }}\n </button>\n\n @if (day.markers.length > 0) {\n <div coarPopoverContent class=\"coar-mini-calendar-marker-popover\">\n <div class=\"coar-mini-calendar-marker-popover__list\">\n @for (marker of getVisibleMarkers(day.markers); track marker.description) {\n <div class=\"coar-mini-calendar-marker-popover__item\">\n {{ marker.description }}\n </div>\n }\n\n @if (getHiddenMarkerCount(day.markers) > 0) {\n <div class=\"coar-mini-calendar-marker-popover__more\">+{{ getHiddenMarkerCount(day.markers) }} other events</div>\n }\n </div>\n </div>\n }\n </coar-popover>\n }\n </div>\n\n @if (showTodayButton()) {\n <div class=\"coar-mini-calendar-footer\">\n <button type=\"button\" class=\"coar-mini-calendar-today\" (click)=\"selectDate(today)\">Today</button>\n </div>\n }\n</div>\n", styles: [":host{display:block}.coar-mini-calendar{padding:var(--coar-spacing-m);min-width:280px;background:var(--coar-background-neutral-primary)}.coar-mini-calendar-header{display:flex;align-items:center;justify-content:space-between;gap:var(--coar-spacing-xs);margin-bottom:var(--coar-spacing-m)}.coar-mini-calendar-nav{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;border-radius:var(--coar-radius-xs);transition:background-color .15s ease,color .15s ease}.coar-mini-calendar-nav:hover{background:var(--coar-background-neutral-secondary);color:var(--coar-icon-neutral-primary)}.coar-mini-calendar-month-year{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;font-family:var(--coar-body-base-family);color:var(--coar-text-neutral-primary);line-height:1.2}.coar-mini-calendar-month{font-size:var(--coar-body-base-size);font-weight:var(--coar-body-base-weight)}.coar-mini-calendar-year{font-size:var(--coar-body-sm-size);font-weight:var(--coar-body-sm-weight);color:var(--coar-text-neutral-secondary)}.coar-mini-calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:var(--coar-spacing-xs)}.coar-mini-calendar-weekdays--with-weeks{grid-template-columns:32px repeat(7,1fr)}.coar-mini-calendar-weekday{display:flex;align-items:center;justify-content:center;height:32px;font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-secondary);text-transform:uppercase}.coar-mini-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.coar-mini-calendar-grid--with-weeks{position:relative;grid-template-columns:32px repeat(7,1fr)}.coar-mini-calendar-grid--with-weeks:before{content:\"\";position:absolute;left:30px;top:0;bottom:0;width:1px;background:var(--coar-border-neutral-secondary);opacity:.15}.coar-mini-calendar-week-number{display:flex;align-items:center;justify-content:center;min-height:32px;font-family:var(--coar-body-caption-family);font-size:10px;color:var(--coar-text-neutral-tertiary);opacity:.6}.coar-mini-calendar-day{display:flex;align-items:center;justify-content:center;width:100%;aspect-ratio:1;min-height:32px;padding:2px;border:none;border-radius:0;background:transparent;background-clip:content-box;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);cursor:pointer;outline:none;transition:background-color .15s ease,color .15s ease}.coar-mini-calendar-day:hover:not(:disabled):not(.coar-mini-calendar-day--selected){background:var(--coar-background-neutral-secondary)}.coar-mini-calendar-day--outside{color:var(--coar-text-neutral-tertiary);opacity:.5}.coar-mini-calendar-day--today:not(.coar-mini-calendar-day--selected){font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);background:var(--coar-background-accent-tertiary)}.coar-mini-calendar-day--selected{background:var(--coar-background-accent-primary);color:var(--coar-text-on-bold);font-weight:var(--coar-body-small-bold-weight)}.coar-mini-calendar-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-mini-calendar-day--focused:not(.coar-mini-calendar-day--selected){outline:2px solid var(--coar-border-accent-primary);outline-offset:-2px}.coar-mini-calendar-day--disabled{color:var(--coar-text-neutral-disabled);cursor:not-allowed}.coar-mini-calendar-day--disabled:hover{background:transparent}.coar-mini-calendar-day--weekend{background:var(--coar-background-neutral-secondary)}.coar-mini-calendar-day--weekend:hover:not(:disabled):not(.coar-mini-calendar-day--selected){background:var(--coar-background-neutral-tertiary)}.coar-mini-calendar-day--weekend.coar-mini-calendar-day--selected{background:var(--coar-background-accent-primary)}.coar-mini-calendar-day--weekend.coar-mini-calendar-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-mini-calendar-day--marked{position:relative}.coar-mini-calendar-day--marked:after{content:\"\";position:absolute;top:2px;left:2px;right:2px;height:3px;border-radius:1px;background:var(--coar-border-semantic-info-subtle);pointer-events:none}.coar-mini-calendar-day--marked.coar-mini-calendar-day--selected:after{background:var(--coar-text-on-bold)}.coar-mini-calendar-marker-popover__list{display:flex;flex-direction:column;gap:var(--coar-spacing-xs)}.coar-mini-calendar-marker-popover__item{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);line-height:1.3}.coar-mini-calendar-marker-popover__more{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-secondary);line-height:1.3}.coar-mini-calendar-footer{display:flex;justify-content:center;margin-top:var(--coar-spacing-m);padding-top:var(--coar-spacing-m);border-top:1px solid var(--coar-border-neutral-tertiary)}.coar-mini-calendar-today{padding:var(--coar-spacing-xs) var(--coar-spacing-m);border:none;border-radius:var(--coar-radius-xs);background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);cursor:pointer;transition:background-color .15s ease}.coar-mini-calendar-today:hover{background:var(--coar-background-accent-tertiary)}\n"], dependencies: [{ kind: "component", type: CoarIconComponent, selector: "coar-icon", inputs: ["name", "source", "size", "rotate", "rotateTransition", "spin", "color", "label"] }, { kind: "component", type: CoarPopoverComponent, selector: "coar-popover", inputs: ["disabled", "openOnHover", "openOnClick", "interactive", "fallbackToBestFit", "clampToViewport"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4397
|
+
}
|
|
4398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarMiniCalendarComponent, decorators: [{
|
|
4399
|
+
type: Component,
|
|
4400
|
+
args: [{ selector: 'coar-mini-calendar', standalone: true, imports: [CoarIconComponent, CoarPopoverComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [CoarPopoverGroupService], template: "<div class=\"coar-mini-calendar\" role=\"application\" (keydown)=\"onKeydown($event)\">\n <div class=\"coar-mini-calendar-header\">\n <button type=\"button\" class=\"coar-mini-calendar-nav\" aria-label=\"Previous year\" (click)=\"previousYear()\">\n <coar-icon name=\"chevrons-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-mini-calendar-nav\" aria-label=\"Previous month\" (click)=\"previousMonth()\">\n <coar-icon name=\"chevron-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n\n <span class=\"coar-mini-calendar-month-year\">\n <span class=\"coar-mini-calendar-month\">{{ viewMonth() }}</span>\n <span class=\"coar-mini-calendar-year\">{{ viewYear() }}</span>\n </span>\n\n <button type=\"button\" class=\"coar-mini-calendar-nav coar-mini-calendar-nav--next\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <coar-icon name=\"chevron-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-mini-calendar-nav coar-mini-calendar-nav--next\" aria-label=\"Next year\" (click)=\"nextYear()\">\n <coar-icon name=\"chevrons-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <div class=\"coar-mini-calendar-weekdays\" [class.coar-mini-calendar-weekdays--with-weeks]=\"showWeekNumbers()\">\n @if (showWeekNumbers()) {\n <span class=\"coar-mini-calendar-week-spacer\"></span>\n }\n @for (day of daysOfWeek(); track day) {\n <span class=\"coar-mini-calendar-weekday\">{{ day }}</span>\n }\n </div>\n\n <div class=\"coar-mini-calendar-grid\" [class.coar-mini-calendar-grid--with-weeks]=\"showWeekNumbers()\" role=\"grid\">\n @for (day of calendarDays(); track day.date.toString(); let i = $index) {\n @if (showWeekNumbers() && i % 7 === 0) {\n <span class=\"coar-mini-calendar-week-number\">{{ weekNumbers()[i / 7] }}</span>\n }\n\n <coar-popover [disabled]=\"day.isDisabled || day.markers.length === 0\" [openOnClick]=\"true\" [openOnHover]=\"true\" [interactive]=\"false\">\n <button\n coarPopoverTrigger\n type=\"button\"\n class=\"coar-mini-calendar-day\"\n [class.coar-mini-calendar-day--outside]=\"day.isOutsideMonth\"\n [class.coar-mini-calendar-day--today]=\"day.isToday\"\n [class.coar-mini-calendar-day--selected]=\"day.isSelected\"\n [class.coar-mini-calendar-day--focused]=\"day.isFocused\"\n [class.coar-mini-calendar-day--disabled]=\"day.isDisabled\"\n [class.coar-mini-calendar-day--weekend]=\"highlightWeekends() && day.isWeekend\"\n [class.coar-mini-calendar-day--marked]=\"day.markers.length > 0\"\n [class]=\"day.markerCssClass\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDate(day.date)\"\n >\n {{ day.day }}\n </button>\n\n @if (day.markers.length > 0) {\n <div coarPopoverContent class=\"coar-mini-calendar-marker-popover\">\n <div class=\"coar-mini-calendar-marker-popover__list\">\n @for (marker of getVisibleMarkers(day.markers); track marker.description) {\n <div class=\"coar-mini-calendar-marker-popover__item\">\n {{ marker.description }}\n </div>\n }\n\n @if (getHiddenMarkerCount(day.markers) > 0) {\n <div class=\"coar-mini-calendar-marker-popover__more\">+{{ getHiddenMarkerCount(day.markers) }} other events</div>\n }\n </div>\n </div>\n }\n </coar-popover>\n }\n </div>\n\n @if (showTodayButton()) {\n <div class=\"coar-mini-calendar-footer\">\n <button type=\"button\" class=\"coar-mini-calendar-today\" (click)=\"selectDate(today)\">Today</button>\n </div>\n }\n</div>\n", styles: [":host{display:block}.coar-mini-calendar{padding:var(--coar-spacing-m);min-width:280px;background:var(--coar-background-neutral-primary)}.coar-mini-calendar-header{display:flex;align-items:center;justify-content:space-between;gap:var(--coar-spacing-xs);margin-bottom:var(--coar-spacing-m)}.coar-mini-calendar-nav{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;border-radius:var(--coar-radius-xs);transition:background-color .15s ease,color .15s ease}.coar-mini-calendar-nav:hover{background:var(--coar-background-neutral-secondary);color:var(--coar-icon-neutral-primary)}.coar-mini-calendar-month-year{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;font-family:var(--coar-body-base-family);color:var(--coar-text-neutral-primary);line-height:1.2}.coar-mini-calendar-month{font-size:var(--coar-body-base-size);font-weight:var(--coar-body-base-weight)}.coar-mini-calendar-year{font-size:var(--coar-body-sm-size);font-weight:var(--coar-body-sm-weight);color:var(--coar-text-neutral-secondary)}.coar-mini-calendar-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:var(--coar-spacing-xs)}.coar-mini-calendar-weekdays--with-weeks{grid-template-columns:32px repeat(7,1fr)}.coar-mini-calendar-weekday{display:flex;align-items:center;justify-content:center;height:32px;font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-secondary);text-transform:uppercase}.coar-mini-calendar-grid{display:grid;grid-template-columns:repeat(7,1fr)}.coar-mini-calendar-grid--with-weeks{position:relative;grid-template-columns:32px repeat(7,1fr)}.coar-mini-calendar-grid--with-weeks:before{content:\"\";position:absolute;left:30px;top:0;bottom:0;width:1px;background:var(--coar-border-neutral-secondary);opacity:.15}.coar-mini-calendar-week-number{display:flex;align-items:center;justify-content:center;min-height:32px;font-family:var(--coar-body-caption-family);font-size:10px;color:var(--coar-text-neutral-tertiary);opacity:.6}.coar-mini-calendar-day{display:flex;align-items:center;justify-content:center;width:100%;aspect-ratio:1;min-height:32px;padding:2px;border:none;border-radius:0;background:transparent;background-clip:content-box;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);cursor:pointer;outline:none;transition:background-color .15s ease,color .15s ease}.coar-mini-calendar-day:hover:not(:disabled):not(.coar-mini-calendar-day--selected){background:var(--coar-background-neutral-secondary)}.coar-mini-calendar-day--outside{color:var(--coar-text-neutral-tertiary);opacity:.5}.coar-mini-calendar-day--today:not(.coar-mini-calendar-day--selected){font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);background:var(--coar-background-accent-tertiary)}.coar-mini-calendar-day--selected{background:var(--coar-background-accent-primary);color:var(--coar-text-on-bold);font-weight:var(--coar-body-small-bold-weight)}.coar-mini-calendar-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-mini-calendar-day--focused:not(.coar-mini-calendar-day--selected){outline:2px solid var(--coar-border-accent-primary);outline-offset:-2px}.coar-mini-calendar-day--disabled{color:var(--coar-text-neutral-disabled);cursor:not-allowed}.coar-mini-calendar-day--disabled:hover{background:transparent}.coar-mini-calendar-day--weekend{background:var(--coar-background-neutral-secondary)}.coar-mini-calendar-day--weekend:hover:not(:disabled):not(.coar-mini-calendar-day--selected){background:var(--coar-background-neutral-tertiary)}.coar-mini-calendar-day--weekend.coar-mini-calendar-day--selected{background:var(--coar-background-accent-primary)}.coar-mini-calendar-day--weekend.coar-mini-calendar-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-mini-calendar-day--marked{position:relative}.coar-mini-calendar-day--marked:after{content:\"\";position:absolute;top:2px;left:2px;right:2px;height:3px;border-radius:1px;background:var(--coar-border-semantic-info-subtle);pointer-events:none}.coar-mini-calendar-day--marked.coar-mini-calendar-day--selected:after{background:var(--coar-text-on-bold)}.coar-mini-calendar-marker-popover__list{display:flex;flex-direction:column;gap:var(--coar-spacing-xs)}.coar-mini-calendar-marker-popover__item{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);line-height:1.3}.coar-mini-calendar-marker-popover__more{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-secondary);line-height:1.3}.coar-mini-calendar-footer{display:flex;justify-content:center;margin-top:var(--coar-spacing-m);padding-top:var(--coar-spacing-m);border-top:1px solid var(--coar-border-neutral-tertiary)}.coar-mini-calendar-today{padding:var(--coar-spacing-xs) var(--coar-spacing-m);border:none;border-radius:var(--coar-radius-xs);background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);cursor:pointer;transition:background-color .15s ease}.coar-mini-calendar-today:hover{background:var(--coar-background-accent-tertiary)}\n"] }]
|
|
4401
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormatConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormatConfig", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], highlightWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightWeekends", required: false }] }], markers: [{ type: i0.Input, args: [{ isSignal: true, alias: "markers", required: false }] }] } });
|
|
4402
|
+
|
|
4016
4403
|
/**
|
|
4017
4404
|
* Date picker component using Temporal API.
|
|
4018
4405
|
*
|
|
@@ -4029,19 +4416,15 @@ function getLocalizedWeekdays(locale, firstDayOfWeek) {
|
|
|
4029
4416
|
* ```
|
|
4030
4417
|
*/
|
|
4031
4418
|
class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
4032
|
-
elementRef = inject(ElementRef);
|
|
4033
4419
|
destroyRef = inject(DestroyRef);
|
|
4034
4420
|
overlayBuilder = createOverlayBuilder();
|
|
4035
4421
|
localizationService = inject(CoarLocalizationService, { optional: true });
|
|
4036
4422
|
localizationDataStore = inject(CoarLocalizationDataStore, { optional: true });
|
|
4037
4423
|
overlayRef = null;
|
|
4038
4424
|
/** Current language from localization service (reactive) */
|
|
4039
|
-
currentLanguage =
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
console.debug('[CoarDatePicker] currentLanguage computed:', lang);
|
|
4043
|
-
return lang;
|
|
4044
|
-
}, ...(ngDevMode ? [{ debugName: "currentLanguage" }] : []));
|
|
4425
|
+
currentLanguage = toSignal(this.localizationService?.languageState.value$ ?? of(''), {
|
|
4426
|
+
initialValue: this.localizationService?.languageState.value ?? '',
|
|
4427
|
+
});
|
|
4045
4428
|
// ============================================================
|
|
4046
4429
|
// Inputs
|
|
4047
4430
|
// ============================================================
|
|
@@ -4084,28 +4467,6 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4084
4467
|
/** Date markers for highlighting special dates (holidays, events, etc.) */
|
|
4085
4468
|
markers = input([], ...(ngDevMode ? [{ debugName: "markers" }] : []));
|
|
4086
4469
|
// ============================================================
|
|
4087
|
-
// Marker Popover Rendering
|
|
4088
|
-
// ============================================================
|
|
4089
|
-
/** Maximum number of lines shown in the marker popover (including "+N" line). */
|
|
4090
|
-
markerPopoverMaxLines = 5;
|
|
4091
|
-
/**
|
|
4092
|
-
* Visible markers before switching to "+N other events".
|
|
4093
|
-
* With a max of 5 lines, we show 4 markers + one summary line.
|
|
4094
|
-
*/
|
|
4095
|
-
markerPopoverVisibleMarkers = 4;
|
|
4096
|
-
getVisibleMarkers(markers) {
|
|
4097
|
-
if (markers.length <= this.markerPopoverMaxLines) {
|
|
4098
|
-
return markers;
|
|
4099
|
-
}
|
|
4100
|
-
return markers.slice(0, this.markerPopoverVisibleMarkers);
|
|
4101
|
-
}
|
|
4102
|
-
getHiddenMarkerCount(markers) {
|
|
4103
|
-
if (markers.length <= this.markerPopoverMaxLines) {
|
|
4104
|
-
return 0;
|
|
4105
|
-
}
|
|
4106
|
-
return Math.max(0, markers.length - this.markerPopoverVisibleMarkers);
|
|
4107
|
-
}
|
|
4108
|
-
// ============================================================
|
|
4109
4470
|
// Model & Outputs
|
|
4110
4471
|
// ============================================================
|
|
4111
4472
|
/** Current selected date (two-way bindable with [(value)]) */
|
|
@@ -4135,20 +4496,8 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4135
4496
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
4136
4497
|
/** Calendar dropdown position (chosen before opening) */
|
|
4137
4498
|
calendarPosition = signal('bottom', ...(ngDevMode ? [{ debugName: "calendarPosition" }] : []));
|
|
4138
|
-
/** Currently viewed month/year in the calendar */
|
|
4139
|
-
viewDate = signal(Temporal.Now.plainDateISO().toPlainYearMonth(), ...(ngDevMode ? [{ debugName: "viewDate" }] : []));
|
|
4140
|
-
/** Focused date in the calendar (for keyboard navigation) */
|
|
4141
|
-
focusedDate = signal(null, ...(ngDevMode ? [{ debugName: "focusedDate" }] : []));
|
|
4142
4499
|
/** Display value for the input field */
|
|
4143
4500
|
displayValue = signal('', ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
4144
|
-
/** Days of week header (localized based on locale and firstDayOfWeek) */
|
|
4145
|
-
daysOfWeek = computed(() => {
|
|
4146
|
-
const locale = this.effectiveLocale();
|
|
4147
|
-
const firstDay = this.firstDayOfWeek();
|
|
4148
|
-
const days = getLocalizedWeekdays(locale, firstDay);
|
|
4149
|
-
console.debug('[CoarDatePicker] daysOfWeek - locale:', locale, 'firstDay:', firstDay, 'days:', days);
|
|
4150
|
-
return days;
|
|
4151
|
-
}, ...(ngDevMode ? [{ debugName: "daysOfWeek" }] : []));
|
|
4152
4501
|
/** Reference to the input element */
|
|
4153
4502
|
inputRef = viewChild('dateInput', ...(ngDevMode ? [{ debugName: "inputRef" }] : []));
|
|
4154
4503
|
/** Reference to the trigger element */
|
|
@@ -4169,9 +4518,9 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4169
4518
|
return directConfig;
|
|
4170
4519
|
}
|
|
4171
4520
|
// 2. Try to get from localization data store (which uses Intl with proper firstDayOfWeek detection)
|
|
4172
|
-
const
|
|
4173
|
-
const localeData =
|
|
4174
|
-
? this.localizationDataStore?.getLocaleData(
|
|
4521
|
+
const storeLocale = this.locale() ?? this.currentLanguage();
|
|
4522
|
+
const localeData = storeLocale
|
|
4523
|
+
? this.localizationDataStore?.getLocaleData(storeLocale)
|
|
4175
4524
|
: undefined;
|
|
4176
4525
|
if (localeData?.date) {
|
|
4177
4526
|
return {
|
|
@@ -4181,25 +4530,8 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4181
4530
|
}
|
|
4182
4531
|
// 3. Fallback to Intl detection (for components without localization service)
|
|
4183
4532
|
const locale = this.effectiveLocale();
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
const parts = formatter.formatToParts(new Date(2024, 0, 15));
|
|
4187
|
-
const dayIndex = parts.findIndex((p) => p.type === 'day');
|
|
4188
|
-
const monthIndex = parts.findIndex((p) => p.type === 'month');
|
|
4189
|
-
const yearIndex = parts.findIndex((p) => p.type === 'year');
|
|
4190
|
-
let pattern = 'dd.mm.yyyy';
|
|
4191
|
-
if (dayIndex < monthIndex && monthIndex < yearIndex)
|
|
4192
|
-
pattern = 'dd.mm.yyyy';
|
|
4193
|
-
else if (monthIndex < dayIndex && dayIndex < yearIndex)
|
|
4194
|
-
pattern = 'mm/dd/yyyy';
|
|
4195
|
-
else if (yearIndex < monthIndex && monthIndex < dayIndex)
|
|
4196
|
-
pattern = 'yyyy-mm-dd';
|
|
4197
|
-
return { pattern, firstDayOfWeek: 1 };
|
|
4198
|
-
}
|
|
4199
|
-
catch {
|
|
4200
|
-
// 4. Final fallback
|
|
4201
|
-
return { pattern: 'dd.mm.yyyy', firstDayOfWeek: 1 };
|
|
4202
|
-
}
|
|
4533
|
+
const detectedPattern = coarDetectDateFormatPatternFromIntl(locale);
|
|
4534
|
+
return { pattern: detectedPattern ?? 'dd.mm.yyyy', firstDayOfWeek: 1 };
|
|
4203
4535
|
}, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
|
|
4204
4536
|
/** Get the date format pattern */
|
|
4205
4537
|
dateFormat = computed(() => this.effectiveDateFormat().pattern, ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
@@ -4207,12 +4539,7 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4207
4539
|
firstDayOfWeek = computed(() => this.effectiveDateFormat().firstDayOfWeek, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
4208
4540
|
/** Get the separator character for the current date format */
|
|
4209
4541
|
separator = computed(() => {
|
|
4210
|
-
|
|
4211
|
-
if (format.includes('.'))
|
|
4212
|
-
return '.';
|
|
4213
|
-
if (format.includes('/'))
|
|
4214
|
-
return '/';
|
|
4215
|
-
return '-';
|
|
4542
|
+
return coarGetDateSeparatorForPattern(this.dateFormat());
|
|
4216
4543
|
}, ...(ngDevMode ? [{ debugName: "separator" }] : []));
|
|
4217
4544
|
/** Get placeholder text based on date format */
|
|
4218
4545
|
inputPlaceholder = computed(() => {
|
|
@@ -4223,94 +4550,12 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4223
4550
|
* Priority: input locale > locale service language > browser locale
|
|
4224
4551
|
*/
|
|
4225
4552
|
effectiveLocale = computed(() => {
|
|
4226
|
-
|
|
4227
|
-
const currentLang = this.currentLanguage();
|
|
4228
|
-
const effective = localeInput ?? currentLang ?? navigator.language;
|
|
4229
|
-
console.debug('[CoarDatePicker] effectiveLocale - input:', localeInput, 'currentLang:', currentLang, 'effective:', effective);
|
|
4230
|
-
return effective;
|
|
4553
|
+
return this.locale() ?? this.currentLanguage() ?? navigator.language;
|
|
4231
4554
|
}, ...(ngDevMode ? [{ debugName: "effectiveLocale" }] : []));
|
|
4232
4555
|
/** Whether the picker has an error state */
|
|
4233
4556
|
hasError = computed(() => this.error(), ...(ngDevMode ? [{ debugName: "hasError" }] : []));
|
|
4234
4557
|
/** Whether the picker is disabled */
|
|
4235
4558
|
isDisabled = computed(() => this.disabled() || this.cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
4236
|
-
/** Calendar grid for current view month */
|
|
4237
|
-
calendarDays = computed(() => {
|
|
4238
|
-
const viewMonth = this.viewDate();
|
|
4239
|
-
const firstDay = viewMonth.toPlainDate({ day: 1 });
|
|
4240
|
-
const daysInMonth = viewMonth.daysInMonth;
|
|
4241
|
-
// Find what day of week the month starts on (1 = Monday, 7 = Sunday in Temporal)
|
|
4242
|
-
const startDayOfWeek = firstDay.dayOfWeek;
|
|
4243
|
-
const firstDayOfWeekSetting = this.firstDayOfWeek();
|
|
4244
|
-
// Calculate days from previous month to show
|
|
4245
|
-
// If firstDayOfWeek is 1 (Monday): offset from Monday
|
|
4246
|
-
// If firstDayOfWeek is 7 (Sunday): offset from Sunday
|
|
4247
|
-
let daysFromPrevMonth;
|
|
4248
|
-
if (firstDayOfWeekSetting === 1) {
|
|
4249
|
-
// Monday first: Monday=0, Tuesday=1, ..., Sunday=6
|
|
4250
|
-
daysFromPrevMonth = (startDayOfWeek - 1 + 7) % 7;
|
|
4251
|
-
}
|
|
4252
|
-
else {
|
|
4253
|
-
// Sunday first: Sunday=0, Monday=1, ..., Saturday=6
|
|
4254
|
-
// Temporal uses: Sunday=7, so we convert
|
|
4255
|
-
daysFromPrevMonth = startDayOfWeek % 7;
|
|
4256
|
-
}
|
|
4257
|
-
const days = [];
|
|
4258
|
-
// Previous month days
|
|
4259
|
-
if (daysFromPrevMonth > 0) {
|
|
4260
|
-
const prevMonth = viewMonth.subtract({ months: 1 });
|
|
4261
|
-
const prevMonthDays = prevMonth.daysInMonth;
|
|
4262
|
-
for (let i = daysFromPrevMonth - 1; i >= 0; i--) {
|
|
4263
|
-
const day = prevMonth.toPlainDate({ day: prevMonthDays - i });
|
|
4264
|
-
days.push(this.createCalendarDay(day, true));
|
|
4265
|
-
}
|
|
4266
|
-
}
|
|
4267
|
-
// Current month days
|
|
4268
|
-
for (let d = 1; d <= daysInMonth; d++) {
|
|
4269
|
-
const day = viewMonth.toPlainDate({ day: d });
|
|
4270
|
-
days.push(this.createCalendarDay(day, false));
|
|
4271
|
-
}
|
|
4272
|
-
// Next month days to fill the grid (6 rows * 7 days = 42)
|
|
4273
|
-
const remainingDays = 42 - days.length;
|
|
4274
|
-
const nextMonth = viewMonth.add({ months: 1 });
|
|
4275
|
-
for (let d = 1; d <= remainingDays; d++) {
|
|
4276
|
-
const day = nextMonth.toPlainDate({ day: d });
|
|
4277
|
-
days.push(this.createCalendarDay(day, true));
|
|
4278
|
-
}
|
|
4279
|
-
return days;
|
|
4280
|
-
}, ...(ngDevMode ? [{ debugName: "calendarDays" }] : []));
|
|
4281
|
-
/** Month name for calendar header */
|
|
4282
|
-
viewMonth = computed(() => {
|
|
4283
|
-
const viewMonth = this.viewDate();
|
|
4284
|
-
const locale = this.effectiveLocale();
|
|
4285
|
-
const formatter = new Intl.DateTimeFormat(locale, {
|
|
4286
|
-
month: 'long',
|
|
4287
|
-
});
|
|
4288
|
-
const jsDate = new Date(viewMonth.year, viewMonth.month - 1, 1);
|
|
4289
|
-
const monthName = formatter.format(jsDate);
|
|
4290
|
-
console.debug('[CoarDatePicker] viewMonth - locale:', locale, 'month:', viewMonth.month, 'name:', monthName);
|
|
4291
|
-
return monthName;
|
|
4292
|
-
}, ...(ngDevMode ? [{ debugName: "viewMonth" }] : []));
|
|
4293
|
-
/** Year for calendar header */
|
|
4294
|
-
viewYear = computed(() => {
|
|
4295
|
-
return this.viewDate().year;
|
|
4296
|
-
}, ...(ngDevMode ? [{ debugName: "viewYear" }] : []));
|
|
4297
|
-
/** Week numbers for each row (6 rows) */
|
|
4298
|
-
weekNumbers = computed(() => {
|
|
4299
|
-
const days = this.calendarDays();
|
|
4300
|
-
const weeks = [];
|
|
4301
|
-
// Get the first day of each week (every 7 days)
|
|
4302
|
-
for (let i = 0; i < 6; i++) {
|
|
4303
|
-
const firstDayOfWeek = days[i * 7];
|
|
4304
|
-
if (firstDayOfWeek) {
|
|
4305
|
-
// weekOfYear may be undefined in some Temporal implementations
|
|
4306
|
-
const weekNum = firstDayOfWeek.date.weekOfYear ?? this.calculateISOWeek(firstDayOfWeek.date);
|
|
4307
|
-
weeks.push(weekNum);
|
|
4308
|
-
}
|
|
4309
|
-
}
|
|
4310
|
-
return weeks;
|
|
4311
|
-
}, ...(ngDevMode ? [{ debugName: "weekNumbers" }] : []));
|
|
4312
|
-
/** Today's date */
|
|
4313
|
-
today = Temporal.Now.plainDateISO();
|
|
4314
4559
|
// ============================================================
|
|
4315
4560
|
// Constructor & Lifecycle
|
|
4316
4561
|
// ============================================================
|
|
@@ -4320,21 +4565,20 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4320
4565
|
effect(() => {
|
|
4321
4566
|
const val = this.value();
|
|
4322
4567
|
if (val) {
|
|
4323
|
-
this.displayValue.set(this.
|
|
4324
|
-
if (!this.isOpen()) {
|
|
4325
|
-
this.viewDate.set(val.toPlainYearMonth());
|
|
4326
|
-
}
|
|
4568
|
+
this.displayValue.set(coarFormatPlainDate(val, this.dateFormat()));
|
|
4327
4569
|
}
|
|
4328
4570
|
else {
|
|
4329
4571
|
this.displayValue.set('');
|
|
4330
4572
|
}
|
|
4331
4573
|
});
|
|
4332
|
-
//
|
|
4333
|
-
|
|
4574
|
+
// Keep Maskito config in sync with date format + constraints.
|
|
4575
|
+
effect(() => {
|
|
4334
4576
|
const inputElement = this.inputRef()?.nativeElement;
|
|
4335
|
-
if (inputElement) {
|
|
4336
|
-
|
|
4577
|
+
if (!inputElement) {
|
|
4578
|
+
return;
|
|
4337
4579
|
}
|
|
4580
|
+
this.maskitoInstance?.destroy();
|
|
4581
|
+
this.initializeMaskito(inputElement);
|
|
4338
4582
|
});
|
|
4339
4583
|
// Cleanup on destroy
|
|
4340
4584
|
this.destroyRef.onDestroy(() => {
|
|
@@ -4373,17 +4617,12 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4373
4617
|
.open({});
|
|
4374
4618
|
this.overlayRef = ref;
|
|
4375
4619
|
this.isOpen.set(true);
|
|
4376
|
-
// Set initial focus date
|
|
4377
|
-
const current = this.value() ?? this.today;
|
|
4378
|
-
this.focusedDate.set(current);
|
|
4379
|
-
this.viewDate.set(current.toPlainYearMonth());
|
|
4380
4620
|
this.opened.emit();
|
|
4381
4621
|
ref.afterClosed$.subscribe(() => {
|
|
4382
4622
|
if (this.overlayRef !== ref)
|
|
4383
4623
|
return;
|
|
4384
4624
|
this.overlayRef = null;
|
|
4385
4625
|
this.isOpen.set(false);
|
|
4386
|
-
this.focusedDate.set(null);
|
|
4387
4626
|
this.closed.emit();
|
|
4388
4627
|
});
|
|
4389
4628
|
}
|
|
@@ -4395,7 +4634,6 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4395
4634
|
this.overlayRef = null;
|
|
4396
4635
|
ref?.close();
|
|
4397
4636
|
this.isOpen.set(false);
|
|
4398
|
-
this.focusedDate.set(null);
|
|
4399
4637
|
this.closed.emit();
|
|
4400
4638
|
}
|
|
4401
4639
|
/** Toggle the calendar dropdown */
|
|
@@ -4407,21 +4645,16 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4407
4645
|
this.openCalendar();
|
|
4408
4646
|
}
|
|
4409
4647
|
}
|
|
4410
|
-
|
|
4411
|
-
|
|
4648
|
+
onMiniCalendarValueChange(date) {
|
|
4649
|
+
if (!date)
|
|
4650
|
+
return;
|
|
4412
4651
|
if (this.isDateDisabled(date))
|
|
4413
4652
|
return;
|
|
4414
4653
|
this.value.set(date);
|
|
4415
4654
|
this.valueChange.emit(date);
|
|
4416
4655
|
this.cvaOnChange(date);
|
|
4417
|
-
// Move keyboard focus to selected date
|
|
4418
|
-
this.focusedDate.set(date);
|
|
4419
4656
|
// Calendar stays open - closes via click outside, Tab, or Escape
|
|
4420
4657
|
}
|
|
4421
|
-
/** Select today's date */
|
|
4422
|
-
selectToday() {
|
|
4423
|
-
this.selectDate(this.today);
|
|
4424
|
-
}
|
|
4425
4658
|
/** Clear the selected date */
|
|
4426
4659
|
clearDate(event) {
|
|
4427
4660
|
event.stopPropagation();
|
|
@@ -4429,27 +4662,6 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4429
4662
|
this.valueChange.emit(null);
|
|
4430
4663
|
this.cvaOnChange(null);
|
|
4431
4664
|
}
|
|
4432
|
-
/** Navigate to previous month */
|
|
4433
|
-
previousMonth() {
|
|
4434
|
-
this.viewDate.update((d) => d.subtract({ months: 1 }));
|
|
4435
|
-
}
|
|
4436
|
-
/** Navigate to next month */
|
|
4437
|
-
nextMonth() {
|
|
4438
|
-
this.viewDate.update((d) => d.add({ months: 1 }));
|
|
4439
|
-
}
|
|
4440
|
-
/** Navigate to previous year */
|
|
4441
|
-
previousYear() {
|
|
4442
|
-
this.viewDate.update((d) => d.subtract({ years: 1 }));
|
|
4443
|
-
}
|
|
4444
|
-
/** Navigate to next year */
|
|
4445
|
-
nextYear() {
|
|
4446
|
-
this.viewDate.update((d) => d.add({ years: 1 }));
|
|
4447
|
-
}
|
|
4448
|
-
/** Go to today's month */
|
|
4449
|
-
goToToday() {
|
|
4450
|
-
this.viewDate.set(this.today.toPlainYearMonth());
|
|
4451
|
-
this.focusedDate.set(this.today);
|
|
4452
|
-
}
|
|
4453
4665
|
// ============================================================
|
|
4454
4666
|
// CVA Methods
|
|
4455
4667
|
// ============================================================
|
|
@@ -4476,63 +4688,6 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4476
4688
|
onTriggerClick() {
|
|
4477
4689
|
this.toggleCalendar();
|
|
4478
4690
|
}
|
|
4479
|
-
onDocumentKeydown(event) {
|
|
4480
|
-
if (!this.isOpen())
|
|
4481
|
-
return;
|
|
4482
|
-
switch (event.key) {
|
|
4483
|
-
case 'Escape':
|
|
4484
|
-
event.preventDefault();
|
|
4485
|
-
this.closeCalendar();
|
|
4486
|
-
break;
|
|
4487
|
-
case 'Enter':
|
|
4488
|
-
case ' ': {
|
|
4489
|
-
event.preventDefault();
|
|
4490
|
-
const focused = this.focusedDate();
|
|
4491
|
-
if (focused) {
|
|
4492
|
-
this.selectDate(focused);
|
|
4493
|
-
}
|
|
4494
|
-
break;
|
|
4495
|
-
}
|
|
4496
|
-
case 'ArrowLeft':
|
|
4497
|
-
event.preventDefault();
|
|
4498
|
-
this.moveFocus(-1, 'day');
|
|
4499
|
-
break;
|
|
4500
|
-
case 'ArrowRight':
|
|
4501
|
-
event.preventDefault();
|
|
4502
|
-
this.moveFocus(1, 'day');
|
|
4503
|
-
break;
|
|
4504
|
-
case 'ArrowUp':
|
|
4505
|
-
event.preventDefault();
|
|
4506
|
-
this.moveFocus(-7, 'day');
|
|
4507
|
-
break;
|
|
4508
|
-
case 'ArrowDown':
|
|
4509
|
-
event.preventDefault();
|
|
4510
|
-
this.moveFocus(7, 'day');
|
|
4511
|
-
break;
|
|
4512
|
-
case 'PageUp':
|
|
4513
|
-
event.preventDefault();
|
|
4514
|
-
if (event.shiftKey) {
|
|
4515
|
-
this.moveFocus(-1, 'year');
|
|
4516
|
-
}
|
|
4517
|
-
else {
|
|
4518
|
-
this.moveFocus(-1, 'month');
|
|
4519
|
-
}
|
|
4520
|
-
break;
|
|
4521
|
-
case 'PageDown':
|
|
4522
|
-
event.preventDefault();
|
|
4523
|
-
if (event.shiftKey) {
|
|
4524
|
-
this.moveFocus(1, 'year');
|
|
4525
|
-
}
|
|
4526
|
-
else {
|
|
4527
|
-
this.moveFocus(1, 'month');
|
|
4528
|
-
}
|
|
4529
|
-
break;
|
|
4530
|
-
case 'Home':
|
|
4531
|
-
event.preventDefault();
|
|
4532
|
-
this.goToToday();
|
|
4533
|
-
break;
|
|
4534
|
-
}
|
|
4535
|
-
}
|
|
4536
4691
|
onTriggerKeydown(event) {
|
|
4537
4692
|
if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
|
|
4538
4693
|
event.preventDefault();
|
|
@@ -4572,7 +4727,6 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4572
4727
|
const parsed = this.parseDateFromInput(text);
|
|
4573
4728
|
if (parsed) {
|
|
4574
4729
|
this.value.set(parsed);
|
|
4575
|
-
this.viewDate.set(parsed.toPlainYearMonth());
|
|
4576
4730
|
this.cvaOnTouched();
|
|
4577
4731
|
this.valueChange.emit(parsed);
|
|
4578
4732
|
}
|
|
@@ -4590,7 +4744,7 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4590
4744
|
// Invalid date entered - reset to current value or clear
|
|
4591
4745
|
const val = this.value();
|
|
4592
4746
|
if (val) {
|
|
4593
|
-
this.displayValue.set(this.
|
|
4747
|
+
this.displayValue.set(coarFormatPlainDate(val, this.dateFormat()));
|
|
4594
4748
|
}
|
|
4595
4749
|
else {
|
|
4596
4750
|
this.displayValue.set('');
|
|
@@ -4621,145 +4775,20 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4621
4775
|
const options = maskitoDateOptionsGenerator({
|
|
4622
4776
|
mode: modeMap[format],
|
|
4623
4777
|
separator,
|
|
4624
|
-
min: minDate ?
|
|
4625
|
-
max: maxDate ?
|
|
4778
|
+
min: minDate ? coarTemporalPlainDateToDate(minDate) : undefined,
|
|
4779
|
+
max: maxDate ? coarTemporalPlainDateToDate(maxDate) : undefined,
|
|
4626
4780
|
});
|
|
4627
4781
|
this.maskitoInstance = new Maskito(inputElement, options);
|
|
4628
4782
|
}
|
|
4629
|
-
/**
|
|
4630
|
-
* Convert Temporal.PlainDate to native Date for Maskito compatibility.
|
|
4631
|
-
*/
|
|
4632
|
-
temporalToDate(temporal) {
|
|
4633
|
-
return new Date(temporal.year, temporal.month - 1, temporal.day);
|
|
4634
|
-
}
|
|
4635
|
-
/**
|
|
4636
|
-
* Calculate ISO week number for a date.
|
|
4637
|
-
* ISO weeks start on Monday and week 1 contains the first Thursday of the year.
|
|
4638
|
-
*/
|
|
4639
|
-
calculateISOWeek(date) {
|
|
4640
|
-
const jsDate = this.temporalToDate(date);
|
|
4641
|
-
const dayOfWeek = jsDate.getDay() || 7; // Convert Sunday (0) to 7
|
|
4642
|
-
// Set to nearest Thursday (ISO week date algorithm)
|
|
4643
|
-
jsDate.setDate(jsDate.getDate() + 4 - dayOfWeek);
|
|
4644
|
-
const yearStart = new Date(jsDate.getFullYear(), 0, 1);
|
|
4645
|
-
// Calculate full weeks to nearest Thursday
|
|
4646
|
-
return Math.ceil(((jsDate.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
|
|
4647
|
-
}
|
|
4648
|
-
/**
|
|
4649
|
-
* Format a Temporal.PlainDate for display according to the configured format.
|
|
4650
|
-
*/
|
|
4651
|
-
formatDateForDisplay(date) {
|
|
4652
|
-
const format = this.dateFormat();
|
|
4653
|
-
const sep = this.separator();
|
|
4654
|
-
const day = String(date.day).padStart(2, '0');
|
|
4655
|
-
const month = String(date.month).padStart(2, '0');
|
|
4656
|
-
const year = String(date.year);
|
|
4657
|
-
switch (format) {
|
|
4658
|
-
case 'dd.mm.yyyy':
|
|
4659
|
-
case 'dd/mm/yyyy':
|
|
4660
|
-
return `${day}${sep}${month}${sep}${year}`;
|
|
4661
|
-
case 'mm/dd/yyyy':
|
|
4662
|
-
return `${month}${sep}${day}${sep}${year}`;
|
|
4663
|
-
case 'yyyy-mm-dd':
|
|
4664
|
-
return `${year}${sep}${month}${sep}${day}`;
|
|
4665
|
-
default:
|
|
4666
|
-
return `${day}${sep}${month}${sep}${year}`;
|
|
4667
|
-
}
|
|
4668
|
-
}
|
|
4669
4783
|
/**
|
|
4670
4784
|
* Parse a date string in the configured format to Temporal.PlainDate.
|
|
4671
4785
|
* Returns null if the string is incomplete or invalid.
|
|
4672
4786
|
*/
|
|
4673
4787
|
parseDateFromInput(text) {
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
if (parts.length !== 3)
|
|
4679
|
-
return null;
|
|
4680
|
-
// Check all parts are complete numbers
|
|
4681
|
-
if (parts.some((p) => p.length === 0 || !/^\d+$/.test(p)))
|
|
4682
|
-
return null;
|
|
4683
|
-
const format = this.dateFormat();
|
|
4684
|
-
let year, month, day;
|
|
4685
|
-
try {
|
|
4686
|
-
switch (format) {
|
|
4687
|
-
case 'dd.mm.yyyy':
|
|
4688
|
-
case 'dd/mm/yyyy':
|
|
4689
|
-
day = parseInt(parts[0], 10);
|
|
4690
|
-
month = parseInt(parts[1], 10);
|
|
4691
|
-
year = parseInt(parts[2], 10);
|
|
4692
|
-
break;
|
|
4693
|
-
case 'mm/dd/yyyy':
|
|
4694
|
-
month = parseInt(parts[0], 10);
|
|
4695
|
-
day = parseInt(parts[1], 10);
|
|
4696
|
-
year = parseInt(parts[2], 10);
|
|
4697
|
-
break;
|
|
4698
|
-
case 'yyyy-mm-dd':
|
|
4699
|
-
year = parseInt(parts[0], 10);
|
|
4700
|
-
month = parseInt(parts[1], 10);
|
|
4701
|
-
day = parseInt(parts[2], 10);
|
|
4702
|
-
break;
|
|
4703
|
-
default:
|
|
4704
|
-
return null;
|
|
4705
|
-
}
|
|
4706
|
-
// Validate ranges before creating Temporal.PlainDate
|
|
4707
|
-
if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31) {
|
|
4708
|
-
return null;
|
|
4709
|
-
}
|
|
4710
|
-
const date = Temporal.PlainDate.from({ year, month, day });
|
|
4711
|
-
// Check against min/max bounds
|
|
4712
|
-
const minDate = this.min();
|
|
4713
|
-
const maxDate = this.max();
|
|
4714
|
-
if (minDate && Temporal.PlainDate.compare(date, minDate) < 0) {
|
|
4715
|
-
return null;
|
|
4716
|
-
}
|
|
4717
|
-
if (maxDate && Temporal.PlainDate.compare(date, maxDate) > 0) {
|
|
4718
|
-
return null;
|
|
4719
|
-
}
|
|
4720
|
-
return date;
|
|
4721
|
-
}
|
|
4722
|
-
catch {
|
|
4723
|
-
// Invalid date (e.g., Feb 30)
|
|
4724
|
-
return null;
|
|
4725
|
-
}
|
|
4726
|
-
}
|
|
4727
|
-
createCalendarDay(date, isOutsideMonth) {
|
|
4728
|
-
const selected = this.value();
|
|
4729
|
-
const focused = this.focusedDate();
|
|
4730
|
-
// Temporal dayOfWeek: 1=Monday ... 6=Saturday, 7=Sunday
|
|
4731
|
-
const dayOfWeek = date.dayOfWeek;
|
|
4732
|
-
const markers = this.getMarkersForDate(date);
|
|
4733
|
-
return {
|
|
4734
|
-
date,
|
|
4735
|
-
day: date.day,
|
|
4736
|
-
isOutsideMonth,
|
|
4737
|
-
isToday: Temporal.PlainDate.compare(date, this.today) === 0,
|
|
4738
|
-
isSelected: selected ? Temporal.PlainDate.compare(date, selected) === 0 : false,
|
|
4739
|
-
isFocused: focused ? Temporal.PlainDate.compare(date, focused) === 0 : false,
|
|
4740
|
-
isDisabled: this.isDateDisabled(date),
|
|
4741
|
-
isWeekend: dayOfWeek === 6 || dayOfWeek === 7,
|
|
4742
|
-
markers,
|
|
4743
|
-
markerCssClass: markers[0]?.cssClass ?? null,
|
|
4744
|
-
};
|
|
4745
|
-
}
|
|
4746
|
-
/**
|
|
4747
|
-
* Find all markers that apply to the given date.
|
|
4748
|
-
* Checks if date falls within any marker's range.
|
|
4749
|
-
*/
|
|
4750
|
-
getMarkersForDate(date) {
|
|
4751
|
-
const markers = this.markers();
|
|
4752
|
-
const matches = [];
|
|
4753
|
-
for (const marker of markers) {
|
|
4754
|
-
const start = marker.startDate;
|
|
4755
|
-
const end = marker.endDate ?? marker.startDate;
|
|
4756
|
-
// Check if date is within marker range (inclusive)
|
|
4757
|
-
if (Temporal.PlainDate.compare(date, start) >= 0 &&
|
|
4758
|
-
Temporal.PlainDate.compare(date, end) <= 0) {
|
|
4759
|
-
matches.push(marker);
|
|
4760
|
-
}
|
|
4761
|
-
}
|
|
4762
|
-
return matches;
|
|
4788
|
+
return coarParsePlainDateFromInput(text, this.dateFormat(), {
|
|
4789
|
+
min: this.min(),
|
|
4790
|
+
max: this.max(),
|
|
4791
|
+
});
|
|
4763
4792
|
}
|
|
4764
4793
|
isDateDisabled(date) {
|
|
4765
4794
|
const minDate = this.min();
|
|
@@ -4772,38 +4801,12 @@ class CoarDatePickerComponent extends CoarControlValueAccessor {
|
|
|
4772
4801
|
}
|
|
4773
4802
|
return false;
|
|
4774
4803
|
}
|
|
4775
|
-
moveFocus(amount, unit) {
|
|
4776
|
-
const current = this.focusedDate() ?? this.value() ?? this.today;
|
|
4777
|
-
let newDate;
|
|
4778
|
-
switch (unit) {
|
|
4779
|
-
case 'day':
|
|
4780
|
-
newDate = current.add({ days: amount });
|
|
4781
|
-
break;
|
|
4782
|
-
case 'month':
|
|
4783
|
-
newDate = current.add({ months: amount });
|
|
4784
|
-
break;
|
|
4785
|
-
case 'year':
|
|
4786
|
-
newDate = current.add({ years: amount });
|
|
4787
|
-
break;
|
|
4788
|
-
}
|
|
4789
|
-
// Check bounds
|
|
4790
|
-
const minDate = this.min();
|
|
4791
|
-
const maxDate = this.max();
|
|
4792
|
-
if (minDate && Temporal.PlainDate.compare(newDate, minDate) < 0) {
|
|
4793
|
-
newDate = minDate;
|
|
4794
|
-
}
|
|
4795
|
-
if (maxDate && Temporal.PlainDate.compare(newDate, maxDate) > 0) {
|
|
4796
|
-
newDate = maxDate;
|
|
4797
|
-
}
|
|
4798
|
-
this.focusedDate.set(newDate);
|
|
4799
|
-
this.viewDate.set(newDate.toPlainYearMonth());
|
|
4800
|
-
}
|
|
4801
4804
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4802
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CoarDatePickerComponent, isStandalone: true, selector: "coar-date-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormatConfig: { classPropertyName: "dateFormatConfig", publicName: "dateFormatConfig", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, highlightWeekends: { classPropertyName: "highlightWeekends", publicName: "highlightWeekends", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange", opened: "opened", closed: "closed" }, host: { listeners: { "document:keydown": "onDocumentKeydown($event)" }, properties: { "class.coar-date-picker--xs": "size() === \"xs\"", "class.coar-date-picker--sm": "size() === \"sm\"", "class.coar-date-picker--md": "size() === \"md\"", "class.coar-date-picker--lg": "size() === \"lg\"", "class.coar-date-picker--disabled": "isDisabled()", "class.coar-date-picker--readonly": "readonly()", "class.coar-date-picker--error": "hasError()", "class.coar-date-picker--open": "isOpen()" } }, providers: [coarProvideValueAccessor(() => CoarDatePickerComponent), CoarPopoverGroupService], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["dateInput"], descendants: true, isSignal: true }, { propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "calendarTemplateRef", first: true, predicate: ["calendarTemplate"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"coar-date-picker-wrapper\">\n <!-- Label -->\n @if (label()) {\n <span class=\"coar-date-picker-label\" [attr.id]=\"labelId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"coar-date-picker-required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n <!-- Trigger -->\n <div\n #trigger\n class=\"coar-date-picker-trigger\"\n [class.coar-date-picker-trigger--disabled]=\"isDisabled()\"\n [class.coar-date-picker-trigger--readonly]=\"readonly()\"\n [class.coar-date-picker-trigger--error]=\"hasError()\"\n [class.coar-date-picker-trigger--open]=\"isOpen()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-controls]=\"isOpen() ? calendarId() : null\"\n role=\"combobox\"\n >\n <!-- Clear Button (left side) - always present to prevent CLS -->\n <coar-icon\n name=\"x\"\n source=\"coar-builtin\"\n size=\"auto\"\n class=\"coar-date-picker-clear\"\n [class.coar-date-picker-clear--hidden]=\"!value() || isDisabled() || readonly()\"\n aria-hidden=\"true\"\n (click)=\"clearDate($event)\"\n />\n\n <!-- Date Input -->\n <input\n #dateInput\n type=\"text\"\n class=\"coar-date-picker-input\"\n [attr.id]=\"inputId()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder() || inputPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [attr.aria-labelledby]=\"label() ? labelId() : null\"\n [attr.aria-invalid]=\"hasError()\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onTriggerKeydown($event)\"\n />\n\n <!-- Calendar Icon (right side) -->\n <button\n type=\"button\"\n class=\"coar-date-picker-calendar-btn\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <coar-icon name=\"calendar\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Calendar Dropdown (rendered via @cocoar/ui-overlay) -->\n <ng-template #calendarTemplate>\n <div\n class=\"coar-date-picker-calendar coar-date-picker-calendar--overlay\"\n [class.coar-date-picker-calendar--top]=\"calendarPosition() === 'top'\"\n [attr.id]=\"calendarId()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Calendar\"\n >\n <!-- Calendar Header -->\n <div class=\"coar-date-picker-header\">\n <button type=\"button\" class=\"coar-date-picker-nav\" aria-label=\"Previous year\" (click)=\"previousYear()\">\n <coar-icon name=\"chevrons-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-date-picker-nav\" aria-label=\"Previous month\" (click)=\"previousMonth()\">\n <coar-icon name=\"chevron-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n\n <span class=\"coar-date-picker-month-year\">\n <span class=\"coar-date-picker-month\">{{ viewMonth() }}</span>\n <span class=\"coar-date-picker-year\">{{ viewYear() }}</span>\n </span>\n\n <button type=\"button\" class=\"coar-date-picker-nav coar-date-picker-nav--next\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <coar-icon name=\"chevron-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-date-picker-nav coar-date-picker-nav--next\" aria-label=\"Next year\" (click)=\"nextYear()\">\n <coar-icon name=\"chevrons-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Days of Week Header -->\n <div class=\"coar-date-picker-weekdays\" [class.coar-date-picker-weekdays--with-weeks]=\"showWeekNumbers()\">\n @if (showWeekNumbers()) {\n <span class=\"coar-date-picker-week-spacer\"></span>\n }\n @for (day of daysOfWeek(); track day) {\n <span class=\"coar-date-picker-weekday\">{{ day }}</span>\n }\n </div>\n\n <!-- Calendar Grid -->\n <div class=\"coar-date-picker-grid\" [class.coar-date-picker-grid--with-weeks]=\"showWeekNumbers()\" role=\"grid\">\n @for (day of calendarDays(); track day.date.toString(); let i = $index) {\n <!-- Week number at start of each row -->\n @if (showWeekNumbers() && i % 7 === 0) {\n <span class=\"coar-date-picker-week-number\">{{ weekNumbers()[i / 7] }}</span>\n }\n <coar-popover [disabled]=\"day.isDisabled || day.markers.length === 0\" [openOnClick]=\"true\" [openOnHover]=\"true\" [interactive]=\"false\">\n <button\n coarPopoverTrigger\n type=\"button\"\n class=\"coar-date-picker-day\"\n [class.coar-date-picker-day--outside]=\"day.isOutsideMonth\"\n [class.coar-date-picker-day--today]=\"day.isToday\"\n [class.coar-date-picker-day--selected]=\"day.isSelected\"\n [class.coar-date-picker-day--focused]=\"day.isFocused\"\n [class.coar-date-picker-day--disabled]=\"day.isDisabled\"\n [class.coar-date-picker-day--weekend]=\"highlightWeekends() && day.isWeekend\"\n [class.coar-date-picker-day--marked]=\"day.markers.length > 0\"\n [class]=\"day.markerCssClass\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDate(day.date)\"\n >\n {{ day.day }}\n </button>\n\n @if (day.markers.length > 0) {\n <div coarPopoverContent class=\"coar-date-picker-marker-popover\">\n <div class=\"coar-date-picker-marker-popover__list\">\n @for (marker of getVisibleMarkers(day.markers); track marker.description) {\n <div class=\"coar-date-picker-marker-popover__item\">\n {{ marker.description }}\n </div>\n }\n\n @if (getHiddenMarkerCount(day.markers) > 0) {\n <div class=\"coar-date-picker-marker-popover__more\">+{{ getHiddenMarkerCount(day.markers) }} other events</div>\n }\n </div>\n </div>\n }\n </coar-popover>\n }\n </div>\n\n <!-- Footer with Today Button -->\n @if (showTodayButton()) {\n <div class=\"coar-date-picker-footer\">\n <button type=\"button\" class=\"coar-date-picker-today\" (click)=\"selectToday()\">Today</button>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Helper/Error Message -->\n @if (message()) {\n <span class=\"coar-date-picker-message\" [class.coar-date-picker-message--error]=\"hasError()\">\n {{ message() }}\n </span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.coar-date-picker-wrapper{display:flex;flex-direction:column;width:100%}.coar-date-picker-label{display:block;margin-bottom:var(--coar-component-md-label-margin);font-family:var(--coar-body-small-bold-family);font-size:var(--coar-component-md-label-font-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-primary);cursor:pointer;-webkit-user-select:none;user-select:none}.coar-date-picker-required{color:var(--coar-text-semantic-error-bold);margin-left:var(--coar-spacing-xs)}:host(.coar-date-picker--xs) .coar-date-picker-label{font-size:var(--coar-component-xs-label-font-size);margin-bottom:var(--coar-component-xs-label-margin)}:host(.coar-date-picker--sm) .coar-date-picker-label{font-size:var(--coar-component-sm-label-font-size);margin-bottom:var(--coar-component-sm-label-margin)}:host(.coar-date-picker--lg) .coar-date-picker-label{font-size:var(--coar-component-lg-label-font-size);margin-bottom:var(--coar-component-lg-label-margin)}.coar-date-picker-trigger{display:flex;align-items:center;gap:var(--coar-spacing-s);height:var(--coar-component-md-height);padding:0;border:1px solid var(--coar-border-input);border-radius:var(--coar-radius-xs);background:var(--coar-surface-input);cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.coar-date-picker-trigger:hover:not(.coar-date-picker-trigger--disabled):not(.coar-date-picker-trigger--readonly):not(.coar-date-picker-trigger--error){border-color:var(--coar-border-input-hover)}.coar-date-picker-trigger:focus,.coar-date-picker-trigger:focus-within{outline:none;border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--open:not(.coar-date-picker-trigger--error){border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--disabled{background:var(--coar-surface-input-disabled);cursor:not-allowed;opacity:.6}.coar-date-picker-trigger--readonly{cursor:default}.coar-date-picker-trigger--error{border-color:var(--coar-border-semantic-error-bold)}.coar-date-picker-trigger--error:focus,.coar-date-picker-trigger--error.coar-date-picker-trigger--open{box-shadow:inset 0 0 0 1px var(--coar-border-semantic-error-bold)}:host(.coar-date-picker--xs) .coar-date-picker-trigger{height:var(--coar-component-xs-height);padding:0 var(--coar-spacing-s);gap:var(--coar-spacing-xs)}:host(.coar-date-picker--sm) .coar-date-picker-trigger{height:var(--coar-component-sm-height);padding:0 var(--coar-spacing-s)}:host(.coar-date-picker--lg) .coar-date-picker-trigger{height:var(--coar-component-lg-height);padding:0 var(--coar-spacing-l)}.coar-date-picker-input{flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);outline:none;cursor:text;text-align:right}.coar-date-picker-input::selection{text-align:right}.coar-date-picker-input::placeholder{color:var(--coar-text-neutral-tertiary)}.coar-date-picker-input:disabled{cursor:not-allowed;color:var(--coar-text-neutral-disabled)}.coar-date-picker-input:read-only{cursor:default}:host(.coar-date-picker--xs) .coar-date-picker-input{font-size:var(--coar-component-xs-font-size)}:host(.coar-date-picker--sm) .coar-date-picker-input{font-size:var(--coar-component-sm-font-size)}:host(.coar-date-picker--lg) .coar-date-picker-input{font-size:var(--coar-component-lg-font-size)}.coar-date-picker-clear{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:var(--coar-spacing-s);color:var(--coar-icon-neutral-disabled);cursor:pointer;transition:color .15s ease,opacity .15s ease;opacity:.4}.coar-date-picker-clear--hidden{opacity:0;pointer-events:none}.coar-date-picker-trigger:hover .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}:host(.coar-date-picker--open) .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}.coar-date-picker-clear:hover:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn{display:flex;align-items:center;justify-content:center;padding:0;margin-right:var(--coar-spacing-s);border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;transition:color .15s ease}.coar-date-picker-calendar-btn:hover:not(:disabled){color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn:disabled{cursor:not-allowed;color:var(--coar-icon-neutral-disabled)}.coar-date-picker-calendar{position:absolute;top:100%;left:0;z-index:1000;margin-top:var(--coar-spacing-xs);padding:var(--coar-spacing-m);min-width:280px;background:var(--coar-background-neutral-primary);border:1px solid var(--coar-border-neutral);border-radius:var(--coar-radius-s);box-shadow:var(--coar-shadow-m)}.coar-date-picker-calendar--overlay{position:static;inset:auto;margin-top:0;margin-bottom:0;z-index:auto}.coar-date-picker-calendar--portal{margin-top:0;margin-bottom:0}.coar-date-picker-calendar--css-anchor{top:anchor(bottom);left:anchor(left);bottom:auto;margin-top:var(--coar-spacing-xs)}.coar-date-picker-calendar--css-anchor.coar-date-picker-calendar--top{top:auto;bottom:anchor(top);margin-top:0;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-calendar--top:not(.coar-date-picker-calendar--overlay):not(.coar-date-picker-calendar--portal):not(.coar-date-picker-calendar--css-anchor){top:auto;bottom:100%;margin-top:0;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-header{display:flex;align-items:center;justify-content:space-between;gap:var(--coar-spacing-xs);margin-bottom:var(--coar-spacing-m)}.coar-date-picker-nav{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;border-radius:var(--coar-radius-xs);transition:background-color .15s ease,color .15s ease}.coar-date-picker-nav:hover{background:var(--coar-background-neutral-secondary);color:var(--coar-icon-neutral-primary)}.coar-date-picker-month-year{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;font-family:var(--coar-body-base-family);color:var(--coar-text-neutral-primary);line-height:1.2}.coar-date-picker-month{font-size:var(--coar-body-base-size);font-weight:var(--coar-body-base-weight)}.coar-date-picker-year{font-size:var(--coar-body-sm-size);font-weight:var(--coar-body-sm-weight);color:var(--coar-text-neutral-secondary)}.coar-date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-weekdays--with-weeks{grid-template-columns:32px repeat(7,1fr)}.coar-date-picker-weekday{display:flex;align-items:center;justify-content:center;height:32px;font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-secondary);text-transform:uppercase}.coar-date-picker-grid{display:grid;grid-template-columns:repeat(7,1fr)}.coar-date-picker-grid--with-weeks{position:relative;grid-template-columns:32px repeat(7,1fr)}.coar-date-picker-grid--with-weeks:before{content:\"\";position:absolute;left:30px;top:0;bottom:0;width:1px;background:var(--coar-border-neutral-secondary);opacity:.15}.coar-date-picker-week-number{display:flex;align-items:center;justify-content:center;min-height:32px;font-family:var(--coar-body-caption-family);font-size:10px;color:var(--coar-text-neutral-tertiary);opacity:.6}.coar-date-picker-day{display:flex;align-items:center;justify-content:center;width:100%;aspect-ratio:1;min-height:32px;padding:2px;border:none;border-radius:0;background:transparent;background-clip:content-box;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);cursor:pointer;outline:none;transition:background-color .15s ease,color .15s ease}.coar-date-picker-day:hover:not(:disabled):not(.coar-date-picker-day--selected){background:var(--coar-background-neutral-secondary)}.coar-date-picker-day--outside{color:var(--coar-text-neutral-tertiary);opacity:.5}.coar-date-picker-day--today:not(.coar-date-picker-day--selected){font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);background:var(--coar-background-accent-tertiary)}.coar-date-picker-day--selected{background:var(--coar-background-accent-primary);color:var(--coar-text-on-bold);font-weight:var(--coar-body-small-bold-weight)}.coar-date-picker-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-date-picker-day--focused:not(.coar-date-picker-day--selected){outline:2px solid var(--coar-border-accent-primary);outline-offset:-2px}.coar-date-picker-day--disabled{color:var(--coar-text-neutral-disabled);cursor:not-allowed}.coar-date-picker-day--disabled:hover{background:transparent}.coar-date-picker-day--weekend{background:var(--coar-background-neutral-secondary)}.coar-date-picker-day--weekend:hover:not(:disabled):not(.coar-date-picker-day--selected){background:var(--coar-background-neutral-tertiary)}.coar-date-picker-day--weekend.coar-date-picker-day--selected{background:var(--coar-background-accent-primary)}.coar-date-picker-day--weekend.coar-date-picker-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-date-picker-day--marked{position:relative}.coar-date-picker-day--marked:after{content:\"\";position:absolute;top:2px;left:2px;right:2px;height:3px;border-radius:1px;background:var(--coar-border-semantic-info-subtle);pointer-events:none}.coar-date-picker-day--marked.coar-date-picker-day--selected:after{background:var(--coar-text-on-bold)}.coar-date-picker-marker-popover__list{display:flex;flex-direction:column;gap:var(--coar-spacing-xs)}.coar-date-picker-marker-popover__item{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);line-height:1.3}.coar-date-picker-marker-popover__more{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-secondary);line-height:1.3}.coar-date-picker-footer{display:flex;justify-content:center;margin-top:var(--coar-spacing-m);padding-top:var(--coar-spacing-m);border-top:1px solid var(--coar-border-neutral-tertiary)}.coar-date-picker-today{padding:var(--coar-spacing-xs) var(--coar-spacing-m);border:none;border-radius:var(--coar-radius-xs);background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);cursor:pointer;transition:background-color .15s ease}.coar-date-picker-today:hover{background:var(--coar-background-accent-tertiary)}.coar-date-picker-message{margin-top:var(--coar-spacing-xs);font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);color:var(--coar-text-neutral-secondary)}.coar-date-picker-message--error{color:var(--coar-text-semantic-error-bold)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: CoarIconComponent, selector: "coar-icon", inputs: ["name", "source", "size", "rotate", "rotateTransition", "spin", "color", "label"] }, { kind: "component", type: CoarPopoverComponent, selector: "coar-popover", inputs: ["disabled", "openOnHover", "openOnClick", "interactive", "fallbackToBestFit", "clampToViewport"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4805
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CoarDatePickerComponent, isStandalone: true, selector: "coar-date-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormatConfig: { classPropertyName: "dateFormatConfig", publicName: "dateFormatConfig", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showWeekNumbers: { classPropertyName: "showWeekNumbers", publicName: "showWeekNumbers", isSignal: true, isRequired: false, transformFunction: null }, highlightWeekends: { classPropertyName: "highlightWeekends", publicName: "highlightWeekends", isSignal: true, isRequired: false, transformFunction: null }, markers: { classPropertyName: "markers", publicName: "markers", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange", opened: "opened", closed: "closed" }, host: { properties: { "class.coar-date-picker--xs": "size() === \"xs\"", "class.coar-date-picker--sm": "size() === \"sm\"", "class.coar-date-picker--md": "size() === \"md\"", "class.coar-date-picker--lg": "size() === \"lg\"", "class.coar-date-picker--disabled": "isDisabled()", "class.coar-date-picker--readonly": "readonly()", "class.coar-date-picker--error": "hasError()", "class.coar-date-picker--open": "isOpen()" } }, providers: [coarProvideValueAccessor(() => CoarDatePickerComponent)], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["dateInput"], descendants: true, isSignal: true }, { propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "calendarTemplateRef", first: true, predicate: ["calendarTemplate"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"coar-date-picker-wrapper\">\n <!-- Label -->\n @if (label()) {\n <span class=\"coar-date-picker-label\" [attr.id]=\"labelId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"coar-date-picker-required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n <!-- Trigger -->\n <div\n #trigger\n class=\"coar-date-picker-trigger\"\n [class.coar-date-picker-trigger--disabled]=\"isDisabled()\"\n [class.coar-date-picker-trigger--readonly]=\"readonly()\"\n [class.coar-date-picker-trigger--error]=\"hasError()\"\n [class.coar-date-picker-trigger--open]=\"isOpen()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-controls]=\"isOpen() ? calendarId() : null\"\n role=\"combobox\"\n >\n <!-- Clear Button (left side) - always present to prevent CLS -->\n <coar-icon\n name=\"x\"\n source=\"coar-builtin\"\n size=\"auto\"\n class=\"coar-date-picker-clear\"\n [class.coar-date-picker-clear--hidden]=\"!value() || isDisabled() || readonly()\"\n aria-hidden=\"true\"\n (click)=\"clearDate($event)\"\n />\n\n <!-- Date Input -->\n <input\n #dateInput\n type=\"text\"\n class=\"coar-date-picker-input\"\n [attr.id]=\"inputId()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder() || inputPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [attr.aria-labelledby]=\"label() ? labelId() : null\"\n [attr.aria-invalid]=\"hasError()\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onTriggerKeydown($event)\"\n />\n\n <!-- Calendar Icon (right side) -->\n <button\n type=\"button\"\n class=\"coar-date-picker-calendar-btn\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <coar-icon name=\"calendar\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Calendar Dropdown (rendered via @cocoar/ui-overlay) -->\n <ng-template #calendarTemplate>\n <div class=\"coar-date-picker-calendar-host\" [attr.id]=\"calendarId()\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Calendar\">\n <coar-mini-calendar\n [value]=\"value()\"\n (valueChange)=\"onMiniCalendarValueChange($event)\"\n [min]=\"min()\"\n [max]=\"max()\"\n [locale]=\"effectiveLocale()\"\n [dateFormatConfig]=\"effectiveDateFormat()\"\n [showTodayButton]=\"showTodayButton()\"\n [showWeekNumbers]=\"showWeekNumbers()\"\n [highlightWeekends]=\"highlightWeekends()\"\n [markers]=\"markers()\"\n />\n </div>\n </ng-template>\n\n <!-- Helper/Error Message -->\n @if (message()) {\n <span class=\"coar-date-picker-message\" [class.coar-date-picker-message--error]=\"hasError()\">\n {{ message() }}\n </span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.coar-date-picker-wrapper{display:flex;flex-direction:column;width:100%}.coar-date-picker-label{display:block;margin-bottom:var(--coar-component-md-label-margin);font-family:var(--coar-body-small-bold-family);font-size:var(--coar-component-md-label-font-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-primary);cursor:pointer;-webkit-user-select:none;user-select:none}.coar-date-picker-required{color:var(--coar-text-semantic-error-bold);margin-left:var(--coar-spacing-xs)}:host(.coar-date-picker--xs) .coar-date-picker-label{font-size:var(--coar-component-xs-label-font-size);margin-bottom:var(--coar-component-xs-label-margin)}:host(.coar-date-picker--sm) .coar-date-picker-label{font-size:var(--coar-component-sm-label-font-size);margin-bottom:var(--coar-component-sm-label-margin)}:host(.coar-date-picker--lg) .coar-date-picker-label{font-size:var(--coar-component-lg-label-font-size);margin-bottom:var(--coar-component-lg-label-margin)}.coar-date-picker-trigger{display:flex;align-items:center;gap:var(--coar-spacing-s);height:var(--coar-component-md-height);padding:0;border:1px solid var(--coar-border-input);border-radius:var(--coar-radius-xs);background:var(--coar-surface-input);cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.coar-date-picker-trigger:hover:not(.coar-date-picker-trigger--disabled):not(.coar-date-picker-trigger--readonly):not(.coar-date-picker-trigger--error){border-color:var(--coar-border-input-hover)}.coar-date-picker-trigger:focus,.coar-date-picker-trigger:focus-within{outline:none;border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--open:not(.coar-date-picker-trigger--error){border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--disabled{background:var(--coar-surface-input-disabled);cursor:not-allowed;opacity:.6}.coar-date-picker-trigger--readonly{cursor:default}.coar-date-picker-trigger--error{border-color:var(--coar-border-semantic-error-bold)}.coar-date-picker-trigger--error:focus,.coar-date-picker-trigger--error.coar-date-picker-trigger--open{box-shadow:inset 0 0 0 1px var(--coar-border-semantic-error-bold)}:host(.coar-date-picker--xs) .coar-date-picker-trigger{height:var(--coar-component-xs-height);padding:0 var(--coar-spacing-s);gap:var(--coar-spacing-xs)}:host(.coar-date-picker--sm) .coar-date-picker-trigger{height:var(--coar-component-sm-height);padding:0 var(--coar-spacing-s)}:host(.coar-date-picker--lg) .coar-date-picker-trigger{height:var(--coar-component-lg-height);padding:0 var(--coar-spacing-l)}.coar-date-picker-input{flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);outline:none;cursor:text;text-align:right}.coar-date-picker-input::selection{text-align:right}.coar-date-picker-input::placeholder{color:var(--coar-text-neutral-tertiary)}.coar-date-picker-input:disabled{cursor:not-allowed;color:var(--coar-text-neutral-disabled)}.coar-date-picker-input:read-only{cursor:default}:host(.coar-date-picker--xs) .coar-date-picker-input{font-size:var(--coar-component-xs-font-size)}:host(.coar-date-picker--sm) .coar-date-picker-input{font-size:var(--coar-component-sm-font-size)}:host(.coar-date-picker--lg) .coar-date-picker-input{font-size:var(--coar-component-lg-font-size)}.coar-date-picker-clear{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:var(--coar-spacing-s);color:var(--coar-icon-neutral-disabled);cursor:pointer;transition:color .15s ease,opacity .15s ease;opacity:.4}.coar-date-picker-clear--hidden{opacity:0;pointer-events:none}.coar-date-picker-trigger:hover .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}:host(.coar-date-picker--open) .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}.coar-date-picker-clear:hover:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn{display:flex;align-items:center;justify-content:center;padding:0;margin-right:var(--coar-spacing-s);border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;transition:color .15s ease}.coar-date-picker-calendar-btn:hover:not(:disabled){color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn:disabled{cursor:not-allowed;color:var(--coar-icon-neutral-disabled)}.coar-date-picker-calendar-host{display:block;border:1px solid var(--coar-border-neutral);border-radius:var(--coar-radius-s);box-shadow:var(--coar-shadow-m)}.coar-date-picker-message{margin-top:var(--coar-spacing-xs);font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);color:var(--coar-text-neutral-secondary)}.coar-date-picker-message--error{color:var(--coar-text-semantic-error-bold)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: CoarIconComponent, selector: "coar-icon", inputs: ["name", "source", "size", "rotate", "rotateTransition", "spin", "color", "label"] }, { kind: "component", type: CoarMiniCalendarComponent, selector: "coar-mini-calendar", inputs: ["value", "min", "max", "locale", "dateFormatConfig", "showTodayButton", "showWeekNumbers", "highlightWeekends", "markers"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4803
4806
|
}
|
|
4804
4807
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoarDatePickerComponent, decorators: [{
|
|
4805
4808
|
type: Component,
|
|
4806
|
-
args: [{ selector: 'coar-date-picker', standalone: true, imports: [FormsModule, CoarIconComponent,
|
|
4809
|
+
args: [{ selector: 'coar-date-picker', standalone: true, imports: [FormsModule, CoarIconComponent, CoarMiniCalendarComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [coarProvideValueAccessor(() => CoarDatePickerComponent)], host: {
|
|
4807
4810
|
'[class.coar-date-picker--xs]': 'size() === "xs"',
|
|
4808
4811
|
'[class.coar-date-picker--sm]': 'size() === "sm"',
|
|
4809
4812
|
'[class.coar-date-picker--md]': 'size() === "md"',
|
|
@@ -4812,13 +4815,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
|
|
|
4812
4815
|
'[class.coar-date-picker--readonly]': 'readonly()',
|
|
4813
4816
|
'[class.coar-date-picker--error]': 'hasError()',
|
|
4814
4817
|
'[class.coar-date-picker--open]': 'isOpen()',
|
|
4815
|
-
|
|
4816
|
-
}, template: "<div class=\"coar-date-picker-wrapper\">\n <!-- Label -->\n @if (label()) {\n <span class=\"coar-date-picker-label\" [attr.id]=\"labelId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"coar-date-picker-required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n <!-- Trigger -->\n <div\n #trigger\n class=\"coar-date-picker-trigger\"\n [class.coar-date-picker-trigger--disabled]=\"isDisabled()\"\n [class.coar-date-picker-trigger--readonly]=\"readonly()\"\n [class.coar-date-picker-trigger--error]=\"hasError()\"\n [class.coar-date-picker-trigger--open]=\"isOpen()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-controls]=\"isOpen() ? calendarId() : null\"\n role=\"combobox\"\n >\n <!-- Clear Button (left side) - always present to prevent CLS -->\n <coar-icon\n name=\"x\"\n source=\"coar-builtin\"\n size=\"auto\"\n class=\"coar-date-picker-clear\"\n [class.coar-date-picker-clear--hidden]=\"!value() || isDisabled() || readonly()\"\n aria-hidden=\"true\"\n (click)=\"clearDate($event)\"\n />\n\n <!-- Date Input -->\n <input\n #dateInput\n type=\"text\"\n class=\"coar-date-picker-input\"\n [attr.id]=\"inputId()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder() || inputPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [attr.aria-labelledby]=\"label() ? labelId() : null\"\n [attr.aria-invalid]=\"hasError()\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onTriggerKeydown($event)\"\n />\n\n <!-- Calendar Icon (right side) -->\n <button\n type=\"button\"\n class=\"coar-date-picker-calendar-btn\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <coar-icon name=\"calendar\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Calendar Dropdown (rendered via @cocoar/ui-overlay) -->\n <ng-template #calendarTemplate>\n <div\n class=\"coar-date-picker-calendar coar-date-picker-calendar--overlay\"\n [class.coar-date-picker-calendar--top]=\"calendarPosition() === 'top'\"\n [attr.id]=\"calendarId()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Calendar\"\n >\n <!-- Calendar Header -->\n <div class=\"coar-date-picker-header\">\n <button type=\"button\" class=\"coar-date-picker-nav\" aria-label=\"Previous year\" (click)=\"previousYear()\">\n <coar-icon name=\"chevrons-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-date-picker-nav\" aria-label=\"Previous month\" (click)=\"previousMonth()\">\n <coar-icon name=\"chevron-left\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n\n <span class=\"coar-date-picker-month-year\">\n <span class=\"coar-date-picker-month\">{{ viewMonth() }}</span>\n <span class=\"coar-date-picker-year\">{{ viewYear() }}</span>\n </span>\n\n <button type=\"button\" class=\"coar-date-picker-nav coar-date-picker-nav--next\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <coar-icon name=\"chevron-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n <button type=\"button\" class=\"coar-date-picker-nav coar-date-picker-nav--next\" aria-label=\"Next year\" (click)=\"nextYear()\">\n <coar-icon name=\"chevrons-right\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Days of Week Header -->\n <div class=\"coar-date-picker-weekdays\" [class.coar-date-picker-weekdays--with-weeks]=\"showWeekNumbers()\">\n @if (showWeekNumbers()) {\n <span class=\"coar-date-picker-week-spacer\"></span>\n }\n @for (day of daysOfWeek(); track day) {\n <span class=\"coar-date-picker-weekday\">{{ day }}</span>\n }\n </div>\n\n <!-- Calendar Grid -->\n <div class=\"coar-date-picker-grid\" [class.coar-date-picker-grid--with-weeks]=\"showWeekNumbers()\" role=\"grid\">\n @for (day of calendarDays(); track day.date.toString(); let i = $index) {\n <!-- Week number at start of each row -->\n @if (showWeekNumbers() && i % 7 === 0) {\n <span class=\"coar-date-picker-week-number\">{{ weekNumbers()[i / 7] }}</span>\n }\n <coar-popover [disabled]=\"day.isDisabled || day.markers.length === 0\" [openOnClick]=\"true\" [openOnHover]=\"true\" [interactive]=\"false\">\n <button\n coarPopoverTrigger\n type=\"button\"\n class=\"coar-date-picker-day\"\n [class.coar-date-picker-day--outside]=\"day.isOutsideMonth\"\n [class.coar-date-picker-day--today]=\"day.isToday\"\n [class.coar-date-picker-day--selected]=\"day.isSelected\"\n [class.coar-date-picker-day--focused]=\"day.isFocused\"\n [class.coar-date-picker-day--disabled]=\"day.isDisabled\"\n [class.coar-date-picker-day--weekend]=\"highlightWeekends() && day.isWeekend\"\n [class.coar-date-picker-day--marked]=\"day.markers.length > 0\"\n [class]=\"day.markerCssClass\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDate(day.date)\"\n >\n {{ day.day }}\n </button>\n\n @if (day.markers.length > 0) {\n <div coarPopoverContent class=\"coar-date-picker-marker-popover\">\n <div class=\"coar-date-picker-marker-popover__list\">\n @for (marker of getVisibleMarkers(day.markers); track marker.description) {\n <div class=\"coar-date-picker-marker-popover__item\">\n {{ marker.description }}\n </div>\n }\n\n @if (getHiddenMarkerCount(day.markers) > 0) {\n <div class=\"coar-date-picker-marker-popover__more\">+{{ getHiddenMarkerCount(day.markers) }} other events</div>\n }\n </div>\n </div>\n }\n </coar-popover>\n }\n </div>\n\n <!-- Footer with Today Button -->\n @if (showTodayButton()) {\n <div class=\"coar-date-picker-footer\">\n <button type=\"button\" class=\"coar-date-picker-today\" (click)=\"selectToday()\">Today</button>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Helper/Error Message -->\n @if (message()) {\n <span class=\"coar-date-picker-message\" [class.coar-date-picker-message--error]=\"hasError()\">\n {{ message() }}\n </span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.coar-date-picker-wrapper{display:flex;flex-direction:column;width:100%}.coar-date-picker-label{display:block;margin-bottom:var(--coar-component-md-label-margin);font-family:var(--coar-body-small-bold-family);font-size:var(--coar-component-md-label-font-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-primary);cursor:pointer;-webkit-user-select:none;user-select:none}.coar-date-picker-required{color:var(--coar-text-semantic-error-bold);margin-left:var(--coar-spacing-xs)}:host(.coar-date-picker--xs) .coar-date-picker-label{font-size:var(--coar-component-xs-label-font-size);margin-bottom:var(--coar-component-xs-label-margin)}:host(.coar-date-picker--sm) .coar-date-picker-label{font-size:var(--coar-component-sm-label-font-size);margin-bottom:var(--coar-component-sm-label-margin)}:host(.coar-date-picker--lg) .coar-date-picker-label{font-size:var(--coar-component-lg-label-font-size);margin-bottom:var(--coar-component-lg-label-margin)}.coar-date-picker-trigger{display:flex;align-items:center;gap:var(--coar-spacing-s);height:var(--coar-component-md-height);padding:0;border:1px solid var(--coar-border-input);border-radius:var(--coar-radius-xs);background:var(--coar-surface-input);cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.coar-date-picker-trigger:hover:not(.coar-date-picker-trigger--disabled):not(.coar-date-picker-trigger--readonly):not(.coar-date-picker-trigger--error){border-color:var(--coar-border-input-hover)}.coar-date-picker-trigger:focus,.coar-date-picker-trigger:focus-within{outline:none;border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--open:not(.coar-date-picker-trigger--error){border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--disabled{background:var(--coar-surface-input-disabled);cursor:not-allowed;opacity:.6}.coar-date-picker-trigger--readonly{cursor:default}.coar-date-picker-trigger--error{border-color:var(--coar-border-semantic-error-bold)}.coar-date-picker-trigger--error:focus,.coar-date-picker-trigger--error.coar-date-picker-trigger--open{box-shadow:inset 0 0 0 1px var(--coar-border-semantic-error-bold)}:host(.coar-date-picker--xs) .coar-date-picker-trigger{height:var(--coar-component-xs-height);padding:0 var(--coar-spacing-s);gap:var(--coar-spacing-xs)}:host(.coar-date-picker--sm) .coar-date-picker-trigger{height:var(--coar-component-sm-height);padding:0 var(--coar-spacing-s)}:host(.coar-date-picker--lg) .coar-date-picker-trigger{height:var(--coar-component-lg-height);padding:0 var(--coar-spacing-l)}.coar-date-picker-input{flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);outline:none;cursor:text;text-align:right}.coar-date-picker-input::selection{text-align:right}.coar-date-picker-input::placeholder{color:var(--coar-text-neutral-tertiary)}.coar-date-picker-input:disabled{cursor:not-allowed;color:var(--coar-text-neutral-disabled)}.coar-date-picker-input:read-only{cursor:default}:host(.coar-date-picker--xs) .coar-date-picker-input{font-size:var(--coar-component-xs-font-size)}:host(.coar-date-picker--sm) .coar-date-picker-input{font-size:var(--coar-component-sm-font-size)}:host(.coar-date-picker--lg) .coar-date-picker-input{font-size:var(--coar-component-lg-font-size)}.coar-date-picker-clear{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:var(--coar-spacing-s);color:var(--coar-icon-neutral-disabled);cursor:pointer;transition:color .15s ease,opacity .15s ease;opacity:.4}.coar-date-picker-clear--hidden{opacity:0;pointer-events:none}.coar-date-picker-trigger:hover .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}:host(.coar-date-picker--open) .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}.coar-date-picker-clear:hover:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn{display:flex;align-items:center;justify-content:center;padding:0;margin-right:var(--coar-spacing-s);border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;transition:color .15s ease}.coar-date-picker-calendar-btn:hover:not(:disabled){color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn:disabled{cursor:not-allowed;color:var(--coar-icon-neutral-disabled)}.coar-date-picker-calendar{position:absolute;top:100%;left:0;z-index:1000;margin-top:var(--coar-spacing-xs);padding:var(--coar-spacing-m);min-width:280px;background:var(--coar-background-neutral-primary);border:1px solid var(--coar-border-neutral);border-radius:var(--coar-radius-s);box-shadow:var(--coar-shadow-m)}.coar-date-picker-calendar--overlay{position:static;inset:auto;margin-top:0;margin-bottom:0;z-index:auto}.coar-date-picker-calendar--portal{margin-top:0;margin-bottom:0}.coar-date-picker-calendar--css-anchor{top:anchor(bottom);left:anchor(left);bottom:auto;margin-top:var(--coar-spacing-xs)}.coar-date-picker-calendar--css-anchor.coar-date-picker-calendar--top{top:auto;bottom:anchor(top);margin-top:0;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-calendar--top:not(.coar-date-picker-calendar--overlay):not(.coar-date-picker-calendar--portal):not(.coar-date-picker-calendar--css-anchor){top:auto;bottom:100%;margin-top:0;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-header{display:flex;align-items:center;justify-content:space-between;gap:var(--coar-spacing-xs);margin-bottom:var(--coar-spacing-m)}.coar-date-picker-nav{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;border-radius:var(--coar-radius-xs);transition:background-color .15s ease,color .15s ease}.coar-date-picker-nav:hover{background:var(--coar-background-neutral-secondary);color:var(--coar-icon-neutral-primary)}.coar-date-picker-month-year{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;font-family:var(--coar-body-base-family);color:var(--coar-text-neutral-primary);line-height:1.2}.coar-date-picker-month{font-size:var(--coar-body-base-size);font-weight:var(--coar-body-base-weight)}.coar-date-picker-year{font-size:var(--coar-body-sm-size);font-weight:var(--coar-body-sm-weight);color:var(--coar-text-neutral-secondary)}.coar-date-picker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:var(--coar-spacing-xs)}.coar-date-picker-weekdays--with-weeks{grid-template-columns:32px repeat(7,1fr)}.coar-date-picker-weekday{display:flex;align-items:center;justify-content:center;height:32px;font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-secondary);text-transform:uppercase}.coar-date-picker-grid{display:grid;grid-template-columns:repeat(7,1fr)}.coar-date-picker-grid--with-weeks{position:relative;grid-template-columns:32px repeat(7,1fr)}.coar-date-picker-grid--with-weeks:before{content:\"\";position:absolute;left:30px;top:0;bottom:0;width:1px;background:var(--coar-border-neutral-secondary);opacity:.15}.coar-date-picker-week-number{display:flex;align-items:center;justify-content:center;min-height:32px;font-family:var(--coar-body-caption-family);font-size:10px;color:var(--coar-text-neutral-tertiary);opacity:.6}.coar-date-picker-day{display:flex;align-items:center;justify-content:center;width:100%;aspect-ratio:1;min-height:32px;padding:2px;border:none;border-radius:0;background:transparent;background-clip:content-box;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);cursor:pointer;outline:none;transition:background-color .15s ease,color .15s ease}.coar-date-picker-day:hover:not(:disabled):not(.coar-date-picker-day--selected){background:var(--coar-background-neutral-secondary)}.coar-date-picker-day--outside{color:var(--coar-text-neutral-tertiary);opacity:.5}.coar-date-picker-day--today:not(.coar-date-picker-day--selected){font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);background:var(--coar-background-accent-tertiary)}.coar-date-picker-day--selected{background:var(--coar-background-accent-primary);color:var(--coar-text-on-bold);font-weight:var(--coar-body-small-bold-weight)}.coar-date-picker-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-date-picker-day--focused:not(.coar-date-picker-day--selected){outline:2px solid var(--coar-border-accent-primary);outline-offset:-2px}.coar-date-picker-day--disabled{color:var(--coar-text-neutral-disabled);cursor:not-allowed}.coar-date-picker-day--disabled:hover{background:transparent}.coar-date-picker-day--weekend{background:var(--coar-background-neutral-secondary)}.coar-date-picker-day--weekend:hover:not(:disabled):not(.coar-date-picker-day--selected){background:var(--coar-background-neutral-tertiary)}.coar-date-picker-day--weekend.coar-date-picker-day--selected{background:var(--coar-background-accent-primary)}.coar-date-picker-day--weekend.coar-date-picker-day--selected:hover{background:var(--coar-background-accent-hover)}.coar-date-picker-day--marked{position:relative}.coar-date-picker-day--marked:after{content:\"\";position:absolute;top:2px;left:2px;right:2px;height:3px;border-radius:1px;background:var(--coar-border-semantic-info-subtle);pointer-events:none}.coar-date-picker-day--marked.coar-date-picker-day--selected:after{background:var(--coar-text-on-bold)}.coar-date-picker-marker-popover__list{display:flex;flex-direction:column;gap:var(--coar-spacing-xs)}.coar-date-picker-marker-popover__item{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);line-height:1.3}.coar-date-picker-marker-popover__more{font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-secondary);line-height:1.3}.coar-date-picker-footer{display:flex;justify-content:center;margin-top:var(--coar-spacing-m);padding-top:var(--coar-spacing-m);border-top:1px solid var(--coar-border-neutral-tertiary)}.coar-date-picker-today{padding:var(--coar-spacing-xs) var(--coar-spacing-m);border:none;border-radius:var(--coar-radius-xs);background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-accent-primary);cursor:pointer;transition:background-color .15s ease}.coar-date-picker-today:hover{background:var(--coar-background-accent-tertiary)}.coar-date-picker-message{margin-top:var(--coar-spacing-xs);font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);color:var(--coar-text-neutral-secondary)}.coar-date-picker-message--error{color:var(--coar-text-semantic-error-bold)}\n"] }]
|
|
4818
|
+
}, template: "<div class=\"coar-date-picker-wrapper\">\n <!-- Label -->\n @if (label()) {\n <span class=\"coar-date-picker-label\" [attr.id]=\"labelId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"coar-date-picker-required\" aria-hidden=\"true\">*</span>\n }\n </span>\n }\n\n <!-- Trigger -->\n <div\n #trigger\n class=\"coar-date-picker-trigger\"\n [class.coar-date-picker-trigger--disabled]=\"isDisabled()\"\n [class.coar-date-picker-trigger--readonly]=\"readonly()\"\n [class.coar-date-picker-trigger--error]=\"hasError()\"\n [class.coar-date-picker-trigger--open]=\"isOpen()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-controls]=\"isOpen() ? calendarId() : null\"\n role=\"combobox\"\n >\n <!-- Clear Button (left side) - always present to prevent CLS -->\n <coar-icon\n name=\"x\"\n source=\"coar-builtin\"\n size=\"auto\"\n class=\"coar-date-picker-clear\"\n [class.coar-date-picker-clear--hidden]=\"!value() || isDisabled() || readonly()\"\n aria-hidden=\"true\"\n (click)=\"clearDate($event)\"\n />\n\n <!-- Date Input -->\n <input\n #dateInput\n type=\"text\"\n class=\"coar-date-picker-input\"\n [attr.id]=\"inputId()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder() || inputPlaceholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [attr.aria-labelledby]=\"label() ? labelId() : null\"\n [attr.aria-invalid]=\"hasError()\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onTriggerKeydown($event)\"\n />\n\n <!-- Calendar Icon (right side) -->\n <button\n type=\"button\"\n class=\"coar-date-picker-calendar-btn\"\n aria-label=\"Open calendar\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"onTriggerClick()\"\n >\n <coar-icon name=\"calendar\" source=\"coar-builtin\" size=\"sm\" />\n </button>\n </div>\n\n <!-- Calendar Dropdown (rendered via @cocoar/ui-overlay) -->\n <ng-template #calendarTemplate>\n <div class=\"coar-date-picker-calendar-host\" [attr.id]=\"calendarId()\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Calendar\">\n <coar-mini-calendar\n [value]=\"value()\"\n (valueChange)=\"onMiniCalendarValueChange($event)\"\n [min]=\"min()\"\n [max]=\"max()\"\n [locale]=\"effectiveLocale()\"\n [dateFormatConfig]=\"effectiveDateFormat()\"\n [showTodayButton]=\"showTodayButton()\"\n [showWeekNumbers]=\"showWeekNumbers()\"\n [highlightWeekends]=\"highlightWeekends()\"\n [markers]=\"markers()\"\n />\n </div>\n </ng-template>\n\n <!-- Helper/Error Message -->\n @if (message()) {\n <span class=\"coar-date-picker-message\" [class.coar-date-picker-message--error]=\"hasError()\">\n {{ message() }}\n </span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.coar-date-picker-wrapper{display:flex;flex-direction:column;width:100%}.coar-date-picker-label{display:block;margin-bottom:var(--coar-component-md-label-margin);font-family:var(--coar-body-small-bold-family);font-size:var(--coar-component-md-label-font-size);font-weight:var(--coar-body-small-bold-weight);color:var(--coar-text-neutral-primary);cursor:pointer;-webkit-user-select:none;user-select:none}.coar-date-picker-required{color:var(--coar-text-semantic-error-bold);margin-left:var(--coar-spacing-xs)}:host(.coar-date-picker--xs) .coar-date-picker-label{font-size:var(--coar-component-xs-label-font-size);margin-bottom:var(--coar-component-xs-label-margin)}:host(.coar-date-picker--sm) .coar-date-picker-label{font-size:var(--coar-component-sm-label-font-size);margin-bottom:var(--coar-component-sm-label-margin)}:host(.coar-date-picker--lg) .coar-date-picker-label{font-size:var(--coar-component-lg-label-font-size);margin-bottom:var(--coar-component-lg-label-margin)}.coar-date-picker-trigger{display:flex;align-items:center;gap:var(--coar-spacing-s);height:var(--coar-component-md-height);padding:0;border:1px solid var(--coar-border-input);border-radius:var(--coar-radius-xs);background:var(--coar-surface-input);cursor:pointer;transition:border-color .15s ease,box-shadow .15s ease}.coar-date-picker-trigger:hover:not(.coar-date-picker-trigger--disabled):not(.coar-date-picker-trigger--readonly):not(.coar-date-picker-trigger--error){border-color:var(--coar-border-input-hover)}.coar-date-picker-trigger:focus,.coar-date-picker-trigger:focus-within{outline:none;border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--open:not(.coar-date-picker-trigger--error){border-color:var(--coar-border-accent-primary);box-shadow:inset 0 0 0 1px var(--coar-border-accent-primary)}.coar-date-picker-trigger--disabled{background:var(--coar-surface-input-disabled);cursor:not-allowed;opacity:.6}.coar-date-picker-trigger--readonly{cursor:default}.coar-date-picker-trigger--error{border-color:var(--coar-border-semantic-error-bold)}.coar-date-picker-trigger--error:focus,.coar-date-picker-trigger--error.coar-date-picker-trigger--open{box-shadow:inset 0 0 0 1px var(--coar-border-semantic-error-bold)}:host(.coar-date-picker--xs) .coar-date-picker-trigger{height:var(--coar-component-xs-height);padding:0 var(--coar-spacing-s);gap:var(--coar-spacing-xs)}:host(.coar-date-picker--sm) .coar-date-picker-trigger{height:var(--coar-component-sm-height);padding:0 var(--coar-spacing-s)}:host(.coar-date-picker--lg) .coar-date-picker-trigger{height:var(--coar-component-lg-height);padding:0 var(--coar-spacing-l)}.coar-date-picker-input{flex:1;min-width:0;height:100%;padding:0;border:none;background:transparent;font-family:var(--coar-body-small-base-family);font-size:var(--coar-body-small-base-size);color:var(--coar-text-neutral-primary);outline:none;cursor:text;text-align:right}.coar-date-picker-input::selection{text-align:right}.coar-date-picker-input::placeholder{color:var(--coar-text-neutral-tertiary)}.coar-date-picker-input:disabled{cursor:not-allowed;color:var(--coar-text-neutral-disabled)}.coar-date-picker-input:read-only{cursor:default}:host(.coar-date-picker--xs) .coar-date-picker-input{font-size:var(--coar-component-xs-font-size)}:host(.coar-date-picker--sm) .coar-date-picker-input{font-size:var(--coar-component-sm-font-size)}:host(.coar-date-picker--lg) .coar-date-picker-input{font-size:var(--coar-component-lg-font-size)}.coar-date-picker-clear{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:var(--coar-spacing-s);color:var(--coar-icon-neutral-disabled);cursor:pointer;transition:color .15s ease,opacity .15s ease;opacity:.4}.coar-date-picker-clear--hidden{opacity:0;pointer-events:none}.coar-date-picker-trigger:hover .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}:host(.coar-date-picker--open) .coar-date-picker-clear:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-tertiary)}.coar-date-picker-clear:hover:not(.coar-date-picker-clear--hidden){opacity:1;color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn{display:flex;align-items:center;justify-content:center;padding:0;margin-right:var(--coar-spacing-s);border:none;background:transparent;color:var(--coar-icon-neutral-secondary);cursor:pointer;transition:color .15s ease}.coar-date-picker-calendar-btn:hover:not(:disabled){color:var(--coar-icon-neutral-primary)}.coar-date-picker-calendar-btn:disabled{cursor:not-allowed;color:var(--coar-icon-neutral-disabled)}.coar-date-picker-calendar-host{display:block;border:1px solid var(--coar-border-neutral);border-radius:var(--coar-radius-s);box-shadow:var(--coar-shadow-m)}.coar-date-picker-message{margin-top:var(--coar-spacing-xs);font-family:var(--coar-body-caption-family);font-size:var(--coar-body-caption-size);color:var(--coar-text-neutral-secondary)}.coar-date-picker-message--error{color:var(--coar-text-semantic-error-bold)}\n"] }]
|
|
4817
4819
|
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormatConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormatConfig", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showWeekNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWeekNumbers", required: false }] }], highlightWeekends: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightWeekends", required: false }] }], markers: [{ type: i0.Input, args: [{ isSignal: true, alias: "markers", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], inputRef: [{ type: i0.ViewChild, args: ['dateInput', { isSignal: true }] }], triggerRef: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], calendarTemplateRef: [{ type: i0.ViewChild, args: ['calendarTemplate', { isSignal: true }] }] } });
|
|
4818
4820
|
|
|
4819
4821
|
/**
|
|
4820
4822
|
* Generated bundle index. Do not edit.
|
|
4821
4823
|
*/
|
|
4822
4824
|
|
|
4823
|
-
export { COAR_BUILTIN_ICON_SOURCE_KEY, COAR_DEFAULT_ICON_SOURCE_KEY, COAR_ICON_SOURCE_ENTRY, CoarBadgeComponent, CoarButtonComponent, CoarCardComponent, CoarCheckboxComponent, CoarCodeBlockComponent, CoarControlValueAccessor, CoarDatePickerComponent, CoarDividerComponent, CoarIconComponent, CoarIconService, CoarLabelComponent, CoarMultiSelectComponent, CoarNoteComponent, CoarNumberInputComponent, CoarPasswordInputComponent, CoarPopoverComponent, CoarPopoverGroupService, CoarScrollbarDirective, CoarSidebarComponent, CoarSingleSelectComponent, CoarTabComponent, CoarTabGroupComponent, CoarTableComponent, CoarTagComponent, CoarTagSelectComponent, CoarTextInputComponent, CoarTooltipDirective, coarProvideValueAccessor, provideCoarDefaultIconSource, provideCoarHttpIconSource, provideCoarIconBuiltInOverrides, provideCoarIconMapSource, provideCoarIconSource };
|
|
4825
|
+
export { COAR_BUILTIN_ICON_SOURCE_KEY, COAR_DEFAULT_ICON_SOURCE_KEY, COAR_ICON_SOURCE_ENTRY, CoarBadgeComponent, CoarButtonComponent, CoarCardComponent, CoarCheckboxComponent, CoarCodeBlockComponent, CoarControlValueAccessor, CoarDatePickerComponent, CoarDividerComponent, CoarIconComponent, CoarIconService, CoarLabelComponent, CoarMiniCalendarComponent, CoarMultiSelectComponent, CoarNoteComponent, CoarNumberInputComponent, CoarPasswordInputComponent, CoarPopoverComponent, CoarPopoverGroupService, CoarScrollbarDirective, CoarSidebarComponent, CoarSingleSelectComponent, CoarTabComponent, CoarTabGroupComponent, CoarTableComponent, CoarTagComponent, CoarTagSelectComponent, CoarTextInputComponent, CoarTooltipDirective, coarCalculateIsoWeekNumber, coarClampPlainDate, coarDetectDateFormatPatternFromIntl, coarFormatPlainDate, coarGetCalendarGridDates, coarGetDateSeparatorForPattern, coarGetLocalizedWeekdays, coarParsePlainDateFromInput, coarProvideValueAccessor, coarTemporalPlainDateToDate, provideCoarDefaultIconSource, provideCoarHttpIconSource, provideCoarIconBuiltInOverrides, provideCoarIconMapSource, provideCoarIconSource };
|
|
4824
4826
|
//# sourceMappingURL=cocoar-ui-components.mjs.map
|