@melodicdev/components 1.5.12 → 1.5.13

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.
@@ -9062,57 +9062,146 @@ FormFieldComponent = __decorate([MelodicComponent({
9062
9062
  "required"
9063
9063
  ]
9064
9064
  })], FormFieldComponent);
9065
+ function dayGrid(c) {
9066
+ return html`
9067
+ <div class="ml-calendar__weekdays" role="row">
9068
+ ${repeat(c.weekdays, (d) => d, (d) => html`
9069
+ <span class="ml-calendar__weekday" role="columnheader">${d}</span>
9070
+ `)}
9071
+ </div>
9072
+
9073
+ <div class="ml-calendar__grid" @keydown=${c.handleGridKeyDown}>
9074
+ ${repeat(c.days, (day) => day.iso, (day) => html`
9075
+ <button
9076
+ type="button"
9077
+ class=${classMap({
9078
+ "ml-calendar__day": true,
9079
+ "ml-calendar__day--other-month": !day.isCurrentMonth,
9080
+ "ml-calendar__day--today": day.isToday,
9081
+ "ml-calendar__day--selected": day.isSelected,
9082
+ "ml-calendar__day--disabled": day.isDisabled
9083
+ })}
9084
+ ?disabled=${day.isDisabled || !day.isCurrentMonth}
9085
+ tabindex=${day.isCurrentMonth ? "0" : "-1"}
9086
+ aria-selected=${day.isSelected ? "true" : "false"}
9087
+ aria-label=${day.iso}
9088
+ @click=${() => c.selectDay(day)}
9089
+ >
9090
+ <span class="ml-calendar__day-number">${day.date}</span>
9091
+ ${day.isToday ? html`<span class="ml-calendar__today-dot"></span>` : ""}
9092
+ </button>
9093
+ `)}
9094
+ </div>
9095
+ `;
9096
+ }
9097
+ function monthGrid(c) {
9098
+ return html`
9099
+ <div class="ml-calendar__cell-grid" @keydown=${c.handleGridKeyDown}>
9100
+ ${repeat(c.months, (m) => m.index, (m) => html`
9101
+ <button
9102
+ type="button"
9103
+ class=${classMap({
9104
+ "ml-calendar__cell": true,
9105
+ "ml-calendar__cell--selected": m.isSelected,
9106
+ "ml-calendar__cell--current": m.isCurrent,
9107
+ "ml-calendar__cell--disabled": m.isDisabled
9108
+ })}
9109
+ ?disabled=${m.isDisabled}
9110
+ tabindex="0"
9111
+ aria-selected=${m.isSelected ? "true" : "false"}
9112
+ aria-label=${m.label}
9113
+ @click=${() => c.selectViewMonth(m)}
9114
+ >
9115
+ ${m.label}
9116
+ </button>
9117
+ `)}
9118
+ </div>
9119
+ `;
9120
+ }
9121
+ function yearGrid(c) {
9122
+ return html`
9123
+ <div class="ml-calendar__cell-grid" @keydown=${c.handleGridKeyDown}>
9124
+ ${repeat(c.years, (y) => y.year, (y) => html`
9125
+ <button
9126
+ type="button"
9127
+ class=${classMap({
9128
+ "ml-calendar__cell": true,
9129
+ "ml-calendar__cell--selected": y.isSelected,
9130
+ "ml-calendar__cell--current": y.isCurrent,
9131
+ "ml-calendar__cell--disabled": y.isDisabled
9132
+ })}
9133
+ ?disabled=${y.isDisabled}
9134
+ tabindex=${y.isDisabled ? "-1" : "0"}
9135
+ aria-selected=${y.isSelected ? "true" : "false"}
9136
+ aria-label=${String(y.year)}
9137
+ @click=${() => c.selectViewYear(y)}
9138
+ >
9139
+ ${y.year}
9140
+ </button>
9141
+ `)}
9142
+ </div>
9143
+ `;
9144
+ }
9065
9145
  function calendarTemplate(c) {
9066
9146
  return html`
9067
- <div class="ml-calendar" role="grid" aria-label=${c.monthLabel}>
9147
+ <div class=${classMap({
9148
+ "ml-calendar": true,
9149
+ [`ml-calendar--view-${c.view}`]: true
9150
+ })} role="grid" aria-label=${c.headerLabel}>
9068
9151
  <div class="ml-calendar__header">
9069
9152
  <div class="ml-calendar__nav-group">
9070
- <button type="button" class="ml-calendar__nav" aria-label="Previous year" @click=${c.prevYear}>
9153
+ <button type="button" class="ml-calendar__nav" aria-label="Previous" @click=${c.headerPrevFar}>
9071
9154
  <ml-icon icon="caret-double-left" size="sm"></ml-icon>
9072
9155
  </button>
9073
- <button type="button" class="ml-calendar__nav" aria-label="Previous month" @click=${c.prevMonth}>
9074
- <ml-icon icon="caret-left" size="sm"></ml-icon>
9075
- </button>
9156
+ ${when(c.view === "day", () => html`
9157
+ <button type="button" class="ml-calendar__nav" aria-label="Previous month" @click=${c.prevMonth}>
9158
+ <ml-icon icon="caret-left" size="sm"></ml-icon>
9159
+ </button>
9160
+ `)}
9076
9161
  </div>
9077
- <span class="ml-calendar__month-label">${c.monthLabel}</span>
9162
+
9163
+ ${when(c.view === "day", () => html`
9164
+ <div class="ml-calendar__title">
9165
+ <button
9166
+ type="button"
9167
+ class="ml-calendar__title-btn"
9168
+ aria-label="Select month"
9169
+ aria-expanded="false"
9170
+ @click=${c.openMonthView}
9171
+ >${c.monthLabel}</button>
9172
+ <button
9173
+ type="button"
9174
+ class="ml-calendar__title-btn"
9175
+ aria-label="Select year"
9176
+ aria-expanded="false"
9177
+ @click=${c.openYearView}
9178
+ >${c.viewYear}</button>
9179
+ </div>
9180
+ `, () => html`
9181
+ <button
9182
+ type="button"
9183
+ class="ml-calendar__title-btn ml-calendar__title-btn--wide"
9184
+ aria-label=${c.view === "month" ? "Back to day view" : "Select year"}
9185
+ aria-expanded="true"
9186
+ @click=${c.view === "month" ? c.openMonthView : c.openYearView}
9187
+ >${c.headerLabel}</button>
9188
+ `)}
9189
+
9078
9190
  <div class="ml-calendar__nav-group">
9079
- <button type="button" class="ml-calendar__nav" aria-label="Next month" @click=${c.nextMonth}>
9080
- <ml-icon icon="caret-right" size="sm"></ml-icon>
9081
- </button>
9082
- <button type="button" class="ml-calendar__nav" aria-label="Next year" @click=${c.nextYear}>
9191
+ ${when(c.view === "day", () => html`
9192
+ <button type="button" class="ml-calendar__nav" aria-label="Next month" @click=${c.nextMonth}>
9193
+ <ml-icon icon="caret-right" size="sm"></ml-icon>
9194
+ </button>
9195
+ `)}
9196
+ <button type="button" class="ml-calendar__nav" aria-label="Next" @click=${c.headerNextFar}>
9083
9197
  <ml-icon icon="caret-double-right" size="sm"></ml-icon>
9084
9198
  </button>
9085
9199
  </div>
9086
9200
  </div>
9087
9201
 
9088
- <div class="ml-calendar__weekdays" role="row">
9089
- ${repeat(c.weekdays, (d) => d, (d) => html`
9090
- <span class="ml-calendar__weekday" role="columnheader">${d}</span>
9091
- `)}
9092
- </div>
9093
-
9094
- <div class="ml-calendar__grid">
9095
- ${repeat(c.days, (day) => day.iso, (day) => html`
9096
- <button
9097
- type="button"
9098
- class=${classMap({
9099
- "ml-calendar__day": true,
9100
- "ml-calendar__day--other-month": !day.isCurrentMonth,
9101
- "ml-calendar__day--today": day.isToday,
9102
- "ml-calendar__day--selected": day.isSelected,
9103
- "ml-calendar__day--disabled": day.isDisabled
9104
- })}
9105
- ?disabled=${day.isDisabled || !day.isCurrentMonth}
9106
- tabindex=${day.isCurrentMonth ? "0" : "-1"}
9107
- aria-selected=${day.isSelected ? "true" : "false"}
9108
- aria-label=${day.iso}
9109
- @click=${() => c.selectDay(day)}
9110
- >
9111
- <span class="ml-calendar__day-number">${day.date}</span>
9112
- ${day.isToday ? html`<span class="ml-calendar__today-dot"></span>` : ""}
9113
- </button>
9114
- `)}
9115
- </div>
9202
+ ${when(c.view === "day", () => dayGrid(c))}
9203
+ ${when(c.view === "month", () => monthGrid(c))}
9204
+ ${when(c.view === "year", () => yearGrid(c))}
9116
9205
 
9117
9206
  <div class="ml-calendar__footer">
9118
9207
  <button type="button" class="ml-calendar__today-btn" @click=${c.goToToday}>Today</button>
@@ -9128,10 +9217,28 @@ const calendarStyles = () => css`
9128
9217
  --ml-calendar-width: 280px;
9129
9218
  --ml-calendar-font-family: var(--ml-font-sans);
9130
9219
 
9131
- /* --- Month label --- */
9220
+ /* --- Month/year title --- */
9132
9221
  --ml-calendar-month-font-size: var(--ml-text-sm);
9133
9222
  --ml-calendar-month-font-weight: var(--ml-font-semibold);
9134
9223
  --ml-calendar-month-color: var(--ml-color-text);
9224
+ --ml-calendar-title-btn-padding-x: var(--ml-space-1-5);
9225
+ --ml-calendar-title-btn-padding-y: var(--ml-space-1);
9226
+ --ml-calendar-title-btn-border-radius: var(--ml-radius-md);
9227
+ --ml-calendar-title-btn-hover-bg: var(--ml-color-surface-raised);
9228
+ --ml-calendar-title-btn-hover-color: var(--ml-color-text);
9229
+
9230
+ /* --- Month/year cells --- */
9231
+ --ml-calendar-cell-font-size: var(--ml-text-sm);
9232
+ --ml-calendar-cell-font-weight: var(--ml-font-regular);
9233
+ --ml-calendar-cell-color: var(--ml-color-text);
9234
+ --ml-calendar-cell-border-radius: var(--ml-radius-md);
9235
+ --ml-calendar-cell-hover-bg: var(--ml-color-surface-raised);
9236
+ --ml-calendar-cell-selected-bg: var(--ml-color-primary);
9237
+ --ml-calendar-cell-selected-color: var(--ml-color-text-inverse);
9238
+ --ml-calendar-cell-selected-font-weight: var(--ml-font-semibold);
9239
+ --ml-calendar-cell-selected-hover-bg: var(--ml-color-primary-hover);
9240
+ --ml-calendar-cell-current-font-weight: var(--ml-font-semibold);
9241
+ --ml-calendar-cell-height: 3rem;
9135
9242
 
9136
9243
  /* --- Nav buttons --- */
9137
9244
  --ml-calendar-nav-size: 2rem;
@@ -9205,10 +9312,94 @@ const calendarStyles = () => css`
9205
9312
  gap: 0;
9206
9313
  }
9207
9314
 
9208
- .ml-calendar__month-label {
9315
+ .ml-calendar__title {
9316
+ display: flex;
9317
+ align-items: center;
9318
+ gap: var(--ml-space-1);
9319
+ }
9320
+
9321
+ .ml-calendar__title-btn {
9322
+ border: none;
9323
+ background: none;
9324
+ padding: var(--ml-calendar-title-btn-padding-y) var(--ml-calendar-title-btn-padding-x);
9325
+ border-radius: var(--ml-calendar-title-btn-border-radius);
9326
+ font-family: inherit;
9209
9327
  font-size: var(--ml-calendar-month-font-size);
9210
9328
  font-weight: var(--ml-calendar-month-font-weight);
9211
9329
  color: var(--ml-calendar-month-color);
9330
+ cursor: pointer;
9331
+ transition: background-color var(--ml-calendar-transition-duration) var(--ml-calendar-transition-easing), color var(--ml-calendar-transition-duration) var(--ml-calendar-transition-easing);
9332
+ }
9333
+
9334
+ .ml-calendar__title-btn:hover {
9335
+ background-color: var(--ml-calendar-title-btn-hover-bg);
9336
+ color: var(--ml-calendar-title-btn-hover-color);
9337
+ }
9338
+
9339
+ .ml-calendar__title-btn:focus-visible {
9340
+ outline: none;
9341
+ box-shadow: var(--ml-calendar-focus-shadow);
9342
+ }
9343
+
9344
+ .ml-calendar__title-btn--wide {
9345
+ min-width: 0;
9346
+ }
9347
+
9348
+ /* Month / year cell grid */
9349
+ .ml-calendar__cell-grid {
9350
+ display: grid;
9351
+ grid-template-columns: repeat(3, 1fr);
9352
+ gap: var(--ml-space-1);
9353
+ padding: var(--ml-space-1) 0;
9354
+ }
9355
+
9356
+ .ml-calendar__cell {
9357
+ display: flex;
9358
+ align-items: center;
9359
+ justify-content: center;
9360
+ height: var(--ml-calendar-cell-height);
9361
+ border: none;
9362
+ border-radius: var(--ml-calendar-cell-border-radius);
9363
+ background: none;
9364
+ font-family: inherit;
9365
+ font-size: var(--ml-calendar-cell-font-size);
9366
+ font-weight: var(--ml-calendar-cell-font-weight);
9367
+ color: var(--ml-calendar-cell-color);
9368
+ cursor: pointer;
9369
+ padding: 0;
9370
+ transition:
9371
+ background-color var(--ml-calendar-transition-duration) var(--ml-calendar-transition-easing),
9372
+ color var(--ml-calendar-transition-duration) var(--ml-calendar-transition-easing);
9373
+ }
9374
+
9375
+ .ml-calendar__cell:hover:not(:disabled):not(.ml-calendar__cell--selected) {
9376
+ background-color: var(--ml-calendar-cell-hover-bg);
9377
+ }
9378
+
9379
+ .ml-calendar__cell:focus-visible {
9380
+ outline: none;
9381
+ box-shadow: var(--ml-calendar-focus-shadow);
9382
+ z-index: 1;
9383
+ }
9384
+
9385
+ .ml-calendar__cell--current {
9386
+ font-weight: var(--ml-calendar-cell-current-font-weight);
9387
+ }
9388
+
9389
+ .ml-calendar__cell--selected {
9390
+ background-color: var(--ml-calendar-cell-selected-bg);
9391
+ color: var(--ml-calendar-cell-selected-color);
9392
+ font-weight: var(--ml-calendar-cell-selected-font-weight);
9393
+ }
9394
+
9395
+ .ml-calendar__cell--selected:hover:not(:disabled) {
9396
+ background-color: var(--ml-calendar-cell-selected-hover-bg);
9397
+ }
9398
+
9399
+ .ml-calendar__cell--disabled,
9400
+ .ml-calendar__cell:disabled {
9401
+ opacity: var(--ml-calendar-disabled-opacity);
9402
+ cursor: not-allowed;
9212
9403
  }
9213
9404
 
9214
9405
  .ml-calendar__nav {
@@ -9380,6 +9571,20 @@ var MONTH_NAMES$1 = [
9380
9571
  "November",
9381
9572
  "December"
9382
9573
  ];
9574
+ var MONTH_NAMES_SHORT = [
9575
+ "Jan",
9576
+ "Feb",
9577
+ "Mar",
9578
+ "Apr",
9579
+ "May",
9580
+ "Jun",
9581
+ "Jul",
9582
+ "Aug",
9583
+ "Sep",
9584
+ "Oct",
9585
+ "Nov",
9586
+ "Dec"
9587
+ ];
9383
9588
  var WEEKDAYS = [
9384
9589
  "Su",
9385
9590
  "Mo",
@@ -9389,6 +9594,9 @@ var WEEKDAYS = [
9389
9594
  "Fr",
9390
9595
  "Sa"
9391
9596
  ];
9597
+ var YEARS_PER_PAGE = 12;
9598
+ var DEFAULT_MIN_YEAR_OFFSET = 120;
9599
+ var DEFAULT_MAX_YEAR_OFFSET = 10;
9392
9600
  function toIso(year, month, day) {
9393
9601
  return `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
9394
9602
  }
@@ -9396,13 +9604,25 @@ function todayIso() {
9396
9604
  const d = /* @__PURE__ */ new Date();
9397
9605
  return toIso(d.getFullYear(), d.getMonth(), d.getDate());
9398
9606
  }
9607
+ function parseYear(val) {
9608
+ if (typeof val === "number" && Number.isFinite(val)) return val;
9609
+ if (typeof val === "string" && val.trim() !== "") {
9610
+ const n = Number.parseInt(val, 10);
9611
+ if (Number.isFinite(n)) return n;
9612
+ }
9613
+ return null;
9614
+ }
9399
9615
  var CalendarComponent = class CalendarComponent$1 {
9400
9616
  constructor() {
9401
9617
  this.value = "";
9402
9618
  this.min = "";
9403
9619
  this.max = "";
9620
+ this.minYear = "";
9621
+ this.maxYear = "";
9404
9622
  this.viewMonth = (/* @__PURE__ */ new Date()).getMonth();
9405
9623
  this.viewYear = (/* @__PURE__ */ new Date()).getFullYear();
9624
+ this.view = "day";
9625
+ this.yearPageStart = 0;
9406
9626
  this.prevYear = () => {
9407
9627
  this.viewYear--;
9408
9628
  };
@@ -9421,6 +9641,55 @@ var CalendarComponent = class CalendarComponent$1 {
9421
9641
  this.viewYear++;
9422
9642
  } else this.viewMonth++;
9423
9643
  };
9644
+ this.headerPrev = () => {
9645
+ if (this.view === "year") this.prevYearPage();
9646
+ else if (this.view === "month") this.prevYear();
9647
+ else this.prevMonth();
9648
+ };
9649
+ this.headerNext = () => {
9650
+ if (this.view === "year") this.nextYearPage();
9651
+ else if (this.view === "month") this.nextYear();
9652
+ else this.nextMonth();
9653
+ };
9654
+ this.headerPrevFar = () => {
9655
+ if (this.view === "year") this.prevYearPage();
9656
+ else this.prevYear();
9657
+ };
9658
+ this.headerNextFar = () => {
9659
+ if (this.view === "year") this.nextYearPage();
9660
+ else this.nextYear();
9661
+ };
9662
+ this.prevYearPage = () => {
9663
+ const next = this.yearPageStart - YEARS_PER_PAGE;
9664
+ const minPage = this.computeYearPageStart(this.resolvedMinYear);
9665
+ this.yearPageStart = Math.max(next, minPage);
9666
+ };
9667
+ this.nextYearPage = () => {
9668
+ const next = this.yearPageStart + YEARS_PER_PAGE;
9669
+ const maxPage = this.computeYearPageStart(this.resolvedMaxYear);
9670
+ this.yearPageStart = Math.min(next, maxPage);
9671
+ };
9672
+ this.openMonthView = () => {
9673
+ this.view = this.view === "month" ? "day" : "month";
9674
+ };
9675
+ this.openYearView = () => {
9676
+ if (this.view === "year") {
9677
+ this.view = "day";
9678
+ return;
9679
+ }
9680
+ this.yearPageStart = this.computeYearPageStart(this.viewYear);
9681
+ this.view = "year";
9682
+ };
9683
+ this.selectViewMonth = (month) => {
9684
+ if (month.isDisabled) return;
9685
+ this.viewMonth = month.index;
9686
+ this.view = "day";
9687
+ };
9688
+ this.selectViewYear = (year) => {
9689
+ if (year.isDisabled) return;
9690
+ this.viewYear = year.year;
9691
+ this.view = "month";
9692
+ };
9424
9693
  this.selectDay = (day) => {
9425
9694
  if (day.isDisabled) return;
9426
9695
  this.value = day.iso;
@@ -9436,6 +9705,7 @@ var CalendarComponent = class CalendarComponent$1 {
9436
9705
  const now = /* @__PURE__ */ new Date();
9437
9706
  this.viewMonth = now.getMonth();
9438
9707
  this.viewYear = now.getFullYear();
9708
+ this.view = "day";
9439
9709
  const iso = todayIso();
9440
9710
  if (!this.isDisabled(iso)) {
9441
9711
  this.value = iso;
@@ -9446,12 +9716,56 @@ var CalendarComponent = class CalendarComponent$1 {
9446
9716
  }));
9447
9717
  }
9448
9718
  };
9719
+ this.handleGridKeyDown = (event) => {
9720
+ const key = event.key;
9721
+ if (key !== "ArrowLeft" && key !== "ArrowRight" && key !== "ArrowUp" && key !== "ArrowDown" && key !== "Home" && key !== "End") return;
9722
+ const target = event.target;
9723
+ if (!target || target.tagName !== "BUTTON") return;
9724
+ const grid = target.closest(".ml-calendar__grid, .ml-calendar__cell-grid");
9725
+ if (!grid) return;
9726
+ const cells = Array.from(grid.querySelectorAll("button:not([disabled])")).filter((el) => el.tabIndex !== -1);
9727
+ if (cells.length === 0) return;
9728
+ const idx = cells.indexOf(target);
9729
+ if (idx === -1) return;
9730
+ const cols = this.view === "day" ? 7 : 3;
9731
+ let nextIdx = idx;
9732
+ switch (key) {
9733
+ case "ArrowLeft":
9734
+ nextIdx = idx - 1;
9735
+ break;
9736
+ case "ArrowRight":
9737
+ nextIdx = idx + 1;
9738
+ break;
9739
+ case "ArrowUp":
9740
+ nextIdx = idx - cols;
9741
+ break;
9742
+ case "ArrowDown":
9743
+ nextIdx = idx + cols;
9744
+ break;
9745
+ case "Home":
9746
+ nextIdx = 0;
9747
+ break;
9748
+ case "End":
9749
+ nextIdx = cells.length - 1;
9750
+ break;
9751
+ }
9752
+ if (nextIdx < 0 || nextIdx >= cells.length) {
9753
+ event.preventDefault();
9754
+ return;
9755
+ }
9756
+ event.preventDefault();
9757
+ cells[nextIdx].focus();
9758
+ };
9449
9759
  }
9450
9760
  onInit() {
9451
9761
  this.navigateToValue();
9762
+ this.yearPageStart = this.computeYearPageStart(this.viewYear);
9452
9763
  }
9453
9764
  onAttributeChange(name, _, newVal) {
9454
- if (name === "value" && newVal) this.navigateToValue();
9765
+ if (name === "value" && newVal) {
9766
+ this.navigateToValue();
9767
+ this.yearPageStart = this.computeYearPageStart(this.viewYear);
9768
+ }
9455
9769
  }
9456
9770
  navigateToValue() {
9457
9771
  if (!this.value) return;
@@ -9462,11 +9776,28 @@ var CalendarComponent = class CalendarComponent$1 {
9462
9776
  }
9463
9777
  }
9464
9778
  get monthLabel() {
9465
- return `${MONTH_NAMES$1[this.viewMonth]} ${this.viewYear}`;
9779
+ return MONTH_NAMES$1[this.viewMonth];
9780
+ }
9781
+ get yearLabel() {
9782
+ return String(this.viewYear);
9783
+ }
9784
+ get yearRangeLabel() {
9785
+ return `${this.yearPageStart} – ${this.yearPageStart + YEARS_PER_PAGE - 1}`;
9786
+ }
9787
+ get headerLabel() {
9788
+ if (this.view === "year") return this.yearRangeLabel;
9789
+ if (this.view === "month") return this.yearLabel;
9790
+ return `${this.monthLabel} ${this.viewYear}`;
9466
9791
  }
9467
9792
  get weekdays() {
9468
9793
  return WEEKDAYS;
9469
9794
  }
9795
+ get resolvedMinYear() {
9796
+ return parseYear(this.minYear) ?? (/* @__PURE__ */ new Date()).getFullYear() - DEFAULT_MIN_YEAR_OFFSET;
9797
+ }
9798
+ get resolvedMaxYear() {
9799
+ return parseYear(this.maxYear) ?? (/* @__PURE__ */ new Date()).getFullYear() + DEFAULT_MAX_YEAR_OFFSET;
9800
+ }
9470
9801
  get days() {
9471
9802
  const year = this.viewYear;
9472
9803
  const month = this.viewMonth;
@@ -9525,6 +9856,66 @@ var CalendarComponent = class CalendarComponent$1 {
9525
9856
  }
9526
9857
  return result;
9527
9858
  }
9859
+ get months() {
9860
+ const selectedMonth = this.selectedMonthForYear(this.viewYear);
9861
+ const now = /* @__PURE__ */ new Date();
9862
+ return MONTH_NAMES_SHORT.map((label, index) => ({
9863
+ index,
9864
+ label,
9865
+ isSelected: selectedMonth === index,
9866
+ isCurrent: now.getFullYear() === this.viewYear && now.getMonth() === index,
9867
+ isDisabled: this.isMonthDisabled(this.viewYear, index)
9868
+ }));
9869
+ }
9870
+ get years() {
9871
+ const result = [];
9872
+ const selectedYear = this.selectedYear();
9873
+ const now = (/* @__PURE__ */ new Date()).getFullYear();
9874
+ const minY = this.resolvedMinYear;
9875
+ const maxY = this.resolvedMaxYear;
9876
+ for (let i = 0; i < YEARS_PER_PAGE; i++) {
9877
+ const year = this.yearPageStart + i;
9878
+ const inRange = year >= minY && year <= maxY;
9879
+ result.push({
9880
+ year,
9881
+ isSelected: selectedYear === year,
9882
+ isCurrent: year === now,
9883
+ isDisabled: !inRange,
9884
+ isPlaceholder: !inRange && (year < minY || year > maxY)
9885
+ });
9886
+ }
9887
+ return result;
9888
+ }
9889
+ get canPageYearsBack() {
9890
+ return this.yearPageStart > this.resolvedMinYear;
9891
+ }
9892
+ get canPageYearsForward() {
9893
+ return this.yearPageStart + YEARS_PER_PAGE - 1 < this.resolvedMaxYear;
9894
+ }
9895
+ computeYearPageStart(year) {
9896
+ const minY = this.resolvedMinYear;
9897
+ return minY + Math.floor((year - minY) / YEARS_PER_PAGE) * YEARS_PER_PAGE;
9898
+ }
9899
+ selectedMonthForYear(year) {
9900
+ if (!this.value) return null;
9901
+ const parts = this.value.split("-");
9902
+ if (parts.length !== 3) return null;
9903
+ if (Number.parseInt(parts[0], 10) !== year) return null;
9904
+ return Number.parseInt(parts[1], 10) - 1;
9905
+ }
9906
+ selectedYear() {
9907
+ if (!this.value) return null;
9908
+ const parts = this.value.split("-");
9909
+ if (parts.length !== 3) return null;
9910
+ return Number.parseInt(parts[0], 10);
9911
+ }
9912
+ isMonthDisabled(year, month) {
9913
+ const monthEnd = toIso(year, month, new Date(year, month + 1, 0).getDate());
9914
+ const monthStart = toIso(year, month, 1);
9915
+ if (this.min && monthEnd < this.min) return true;
9916
+ if (this.max && monthStart > this.max) return true;
9917
+ return false;
9918
+ }
9528
9919
  isDisabled(iso) {
9529
9920
  if (this.min && iso < this.min) return true;
9530
9921
  if (this.max && iso > this.max) return true;
@@ -9538,7 +9929,9 @@ CalendarComponent = __decorate([MelodicComponent({
9538
9929
  attributes: [
9539
9930
  "value",
9540
9931
  "min",
9541
- "max"
9932
+ "max",
9933
+ "min-year",
9934
+ "max-year"
9542
9935
  ]
9543
9936
  })], CalendarComponent);
9544
9937
  function datePickerTemplate(c) {
@@ -9590,6 +9983,8 @@ function datePickerTemplate(c) {
9590
9983
  value=${c.value}
9591
9984
  min=${c.min}
9592
9985
  max=${c.max}
9986
+ min-year=${c.minYear}
9987
+ max-year=${c.maxYear}
9593
9988
  @ml:select=${c.handleDateSelect}
9594
9989
  ></ml-calendar>
9595
9990
  </div>
@@ -9846,6 +10241,8 @@ var DatePickerComponent = class DatePickerComponent$1 {
9846
10241
  this.required = false;
9847
10242
  this.min = "";
9848
10243
  this.max = "";
10244
+ this.minYear = "";
10245
+ this.maxYear = "";
9849
10246
  this.isOpen = false;
9850
10247
  this._cleanupAutoUpdate = null;
9851
10248
  this.toggleCalendar = () => {
@@ -9961,7 +10358,9 @@ DatePickerComponent = __decorate([MelodicComponent({
9961
10358
  "disabled",
9962
10359
  "required",
9963
10360
  "min",
9964
- "max"
10361
+ "max",
10362
+ "min-year",
10363
+ "max-year"
9965
10364
  ]
9966
10365
  })], DatePickerComponent);
9967
10366
  function alertTemplate(c) {