@progressive-development/pd-calendar 0.9.2 → 1.0.0

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.
Files changed (118) hide show
  1. package/LICENSE +21 -2
  2. package/README.md +32 -57
  3. package/dist/generated/locales/be.d.ts +3 -0
  4. package/dist/generated/locales/be.d.ts.map +1 -1
  5. package/dist/generated/locales/de.d.ts +3 -0
  6. package/dist/generated/locales/de.d.ts.map +1 -1
  7. package/dist/generated/locales/en.d.ts +3 -0
  8. package/dist/generated/locales/en.d.ts.map +1 -1
  9. package/dist/index.d.ts +10 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +16 -0
  12. package/dist/locales/be.js +4 -1
  13. package/dist/locales/de.js +3 -0
  14. package/dist/locales/en.js +4 -1
  15. package/dist/pd-calendar/PdCalendar.d.ts +101 -18
  16. package/dist/pd-calendar/PdCalendar.d.ts.map +1 -1
  17. package/dist/pd-calendar/PdCalendar.js +380 -264
  18. package/dist/pd-calendar/pd-calendar-cell/PdCalendarCell.d.ts +40 -33
  19. package/dist/pd-calendar/pd-calendar-cell/PdCalendarCell.d.ts.map +1 -1
  20. package/dist/pd-calendar/pd-calendar-cell/PdCalendarCell.js +173 -113
  21. package/dist/pd-calendar/pd-calendar-day-events-panel/PdCalendarDayEventsPanel.d.ts +27 -0
  22. package/dist/pd-calendar/pd-calendar-day-events-panel/PdCalendarDayEventsPanel.d.ts.map +1 -0
  23. package/dist/pd-calendar/pd-calendar-day-events-panel/PdCalendarDayEventsPanel.js +160 -0
  24. package/dist/pd-calendar/pd-calendar-day-events-panel/pd-calendar-day-events-panel.d.ts +3 -0
  25. package/dist/pd-calendar/pd-calendar-day-events-panel/pd-calendar-day-events-panel.d.ts.map +1 -0
  26. package/dist/pd-calendar/pd-calendar-day-events-panel/pd-calendar-day-events-panel.js +8 -0
  27. package/dist/pd-calendar/pd-calendar-event-cell/PdCalendarEventCell.d.ts +55 -0
  28. package/dist/pd-calendar/pd-calendar-event-cell/PdCalendarEventCell.d.ts.map +1 -0
  29. package/dist/pd-calendar/pd-calendar-event-cell/PdCalendarEventCell.js +341 -0
  30. package/dist/pd-calendar/pd-calendar-event-cell/pd-calendar-event-cell.d.ts +3 -0
  31. package/dist/pd-calendar/pd-calendar-event-cell/pd-calendar-event-cell.d.ts.map +1 -0
  32. package/dist/pd-calendar/pd-calendar-event-cell/pd-calendar-event-cell.js +8 -0
  33. package/dist/pd-calendar/pd-calendar-event-info-panel/PdCalendarEventInfoPanel.d.ts +29 -0
  34. package/dist/pd-calendar/pd-calendar-event-info-panel/PdCalendarEventInfoPanel.d.ts.map +1 -0
  35. package/dist/pd-calendar/pd-calendar-event-info-panel/PdCalendarEventInfoPanel.js +211 -0
  36. package/dist/pd-calendar/pd-calendar-event-info-panel/pd-calendar-event-info-panel.d.ts +3 -0
  37. package/dist/pd-calendar/pd-calendar-event-info-panel/pd-calendar-event-info-panel.d.ts.map +1 -0
  38. package/dist/pd-calendar/pd-calendar-event-info-panel/pd-calendar-event-info-panel.js +8 -0
  39. package/dist/pd-calendar/pd-calendar-list-cell/PdCalendarListCell.d.ts +28 -0
  40. package/dist/pd-calendar/pd-calendar-list-cell/PdCalendarListCell.d.ts.map +1 -0
  41. package/dist/pd-calendar/pd-calendar-list-cell/PdCalendarListCell.js +252 -0
  42. package/dist/pd-calendar/pd-calendar-list-cell/pd-calendar-list-cell.d.ts +3 -0
  43. package/dist/pd-calendar/pd-calendar-list-cell/pd-calendar-list-cell.d.ts.map +1 -0
  44. package/dist/pd-calendar/pd-calendar-list-cell/pd-calendar-list-cell.js +8 -0
  45. package/dist/pd-calendar/pd-calendar-list-view/PdCalendarListView.d.ts +26 -0
  46. package/dist/pd-calendar/pd-calendar-list-view/PdCalendarListView.d.ts.map +1 -0
  47. package/dist/pd-calendar/pd-calendar-list-view/PdCalendarListView.js +165 -0
  48. package/dist/pd-calendar/pd-calendar-list-view/pd-calendar-list-view.d.ts +3 -0
  49. package/dist/pd-calendar/pd-calendar-list-view/pd-calendar-list-view.d.ts.map +1 -0
  50. package/dist/pd-calendar/pd-calendar-list-view/pd-calendar-list-view.js +8 -0
  51. package/dist/pd-calendar/pd-calendar-month-view/PdCalendarMonthView.d.ts +55 -0
  52. package/dist/pd-calendar/pd-calendar-month-view/PdCalendarMonthView.d.ts.map +1 -0
  53. package/dist/pd-calendar/pd-calendar-month-view/PdCalendarMonthView.js +461 -0
  54. package/dist/pd-calendar/pd-calendar-month-view/pd-calendar-month-view.d.ts +3 -0
  55. package/dist/pd-calendar/pd-calendar-month-view/pd-calendar-month-view.d.ts.map +1 -0
  56. package/dist/pd-calendar/pd-calendar-month-view/pd-calendar-month-view.js +8 -0
  57. package/dist/pd-calendar/pd-calendar-time-grid-view/PdCalendarTimeGridView.d.ts +32 -0
  58. package/dist/pd-calendar/pd-calendar-time-grid-view/PdCalendarTimeGridView.d.ts.map +1 -0
  59. package/dist/pd-calendar/pd-calendar-time-grid-view/PdCalendarTimeGridView.js +468 -0
  60. package/dist/pd-calendar/pd-calendar-time-grid-view/pd-calendar-time-grid-view.d.ts +3 -0
  61. package/dist/pd-calendar/pd-calendar-time-grid-view/pd-calendar-time-grid-view.d.ts.map +1 -0
  62. package/dist/pd-calendar/pd-calendar-time-grid-view/pd-calendar-time-grid-view.js +8 -0
  63. package/dist/pd-calendar/pd-calendar-week-cell/PdCalendarWeekCell.d.ts +31 -0
  64. package/dist/pd-calendar/pd-calendar-week-cell/PdCalendarWeekCell.d.ts.map +1 -0
  65. package/dist/pd-calendar/pd-calendar-week-cell/PdCalendarWeekCell.js +134 -0
  66. package/dist/pd-calendar/pd-calendar-week-cell/pd-calendar-week-cell.d.ts +3 -0
  67. package/dist/pd-calendar/pd-calendar-week-cell/pd-calendar-week-cell.d.ts.map +1 -0
  68. package/dist/pd-calendar/pd-calendar-week-cell/pd-calendar-week-cell.js +8 -0
  69. package/dist/pd-calendar/pd-calendar.stories.d.ts +79 -19
  70. package/dist/pd-calendar/pd-calendar.stories.d.ts.map +1 -1
  71. package/dist/pd-calendar/pd-year-popup/PdYearPopup.d.ts +22 -11
  72. package/dist/pd-calendar/pd-year-popup/PdYearPopup.d.ts.map +1 -1
  73. package/dist/pd-calendar/pd-year-popup/PdYearPopup.js +152 -34
  74. package/dist/pd-datepicker/PdDatepicker.d.ts +76 -7
  75. package/dist/pd-datepicker/PdDatepicker.d.ts.map +1 -1
  76. package/dist/pd-datepicker/PdDatepicker.js +257 -50
  77. package/dist/pd-datepicker/pd-date-picker.stories.d.ts +78 -20
  78. package/dist/pd-datepicker/pd-date-picker.stories.d.ts.map +1 -1
  79. package/dist/pd-slot-picker/PdSlotPicker.d.ts +102 -0
  80. package/dist/pd-slot-picker/PdSlotPicker.d.ts.map +1 -0
  81. package/dist/pd-slot-picker/PdSlotPicker.js +339 -0
  82. package/dist/pd-slot-picker/pd-slot-cell/PdSlotCell.d.ts +35 -0
  83. package/dist/pd-slot-picker/pd-slot-cell/PdSlotCell.d.ts.map +1 -0
  84. package/dist/pd-slot-picker/pd-slot-cell/PdSlotCell.js +188 -0
  85. package/dist/pd-slot-picker/pd-slot-cell/pd-slot-cell.d.ts +3 -0
  86. package/dist/pd-slot-picker/pd-slot-cell/pd-slot-cell.d.ts.map +1 -0
  87. package/dist/pd-slot-picker/pd-slot-cell/pd-slot-cell.js +8 -0
  88. package/dist/pd-slot-picker/pd-slot-picker.d.ts +3 -0
  89. package/dist/pd-slot-picker/pd-slot-picker.d.ts.map +1 -0
  90. package/dist/pd-slot-picker/pd-slot-picker.stories.d.ts +67 -0
  91. package/dist/pd-slot-picker/pd-slot-picker.stories.d.ts.map +1 -0
  92. package/dist/pd-slot-picker.d.ts +2 -0
  93. package/dist/pd-slot-picker.js +8 -0
  94. package/dist/shared/PdBaseCell.d.ts +68 -0
  95. package/dist/shared/PdBaseCell.d.ts.map +1 -0
  96. package/dist/shared/PdBaseCell.js +120 -0
  97. package/dist/shared/PdBaseView.d.ts +22 -0
  98. package/dist/shared/PdBaseView.d.ts.map +1 -0
  99. package/dist/shared/PdBaseView.js +46 -0
  100. package/dist/shared/PdCalendarPanelBase.d.ts +34 -0
  101. package/dist/shared/PdCalendarPanelBase.d.ts.map +1 -0
  102. package/dist/shared/PdCalendarPanelBase.js +169 -0
  103. package/dist/shared/calendar-button-bar/calendar-button-bar.d.ts +41 -0
  104. package/dist/shared/calendar-button-bar/calendar-button-bar.d.ts.map +1 -0
  105. package/dist/shared/calendar-button-bar/calendar-button-bar.js +435 -0
  106. package/dist/shared/calendar-locales.d.ts +9 -0
  107. package/dist/shared/calendar-locales.d.ts.map +1 -0
  108. package/dist/shared/calendar-locales.js +30 -0
  109. package/dist/shared/calendar-utils.d.ts +34 -0
  110. package/dist/shared/calendar-utils.d.ts.map +1 -0
  111. package/dist/shared/calendar-utils.js +99 -0
  112. package/dist/shared/calendar-utils.test.d.ts +2 -0
  113. package/dist/shared/calendar-utils.test.d.ts.map +1 -0
  114. package/dist/types.d.ts +102 -1
  115. package/dist/types.d.ts.map +1 -1
  116. package/package.json +10 -5
  117. package/dist/pd-calendar/pd-calendar-cell/pd-calendar-cell.stories.d.ts +0 -15
  118. package/dist/pd-calendar/pd-calendar-cell/pd-calendar-cell.stories.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { css, html } from 'lit';
1
+ import { css, nothing, html } from 'lit';
2
2
  import { localized, msg } from '@lit/localize';
3
3
  import { property, state } from 'lit/decorators.js';
4
4
  import { parse, format } from 'date-fns';
@@ -22,8 +22,7 @@ var __decorateClass = (decorators, target, key, kind) => {
22
22
  const UNDEF = "UNDEF";
23
23
  const INPUT_TYPE_DATE = 7;
24
24
  const DEFAULT_FORMAT = "yyyy-MM-dd";
25
- const DATE_TIMES = [
26
- { name: "Uhrzeit auswählen", value: UNDEF },
25
+ const TIME_VALUES = [
27
26
  { name: "07:00", value: "07:00" },
28
27
  { name: "07:30", value: "07:30" },
29
28
  { name: "08:00", value: "08:00" },
@@ -63,7 +62,7 @@ function getDataForDaysBetween(start, end) {
63
62
  let to = new Date(end);
64
63
  if (from > to) [from, to] = [to, from];
65
64
  while (from <= to) {
66
- result[format(from, DEFAULT_FORMAT)] = [{ special: true }];
65
+ result[format(from, DEFAULT_FORMAT)] = [{ category: "range" }];
67
66
  from.setDate(from.getDate() + 1);
68
67
  }
69
68
  return result;
@@ -75,12 +74,38 @@ let PdDatepicker = class extends PdBaseInputElement {
75
74
  this.hideToday = false;
76
75
  this.withYearPopup = [];
77
76
  this.withTime = false;
77
+ this.disabledDays = [];
78
+ this.modal = false;
79
+ this.modalBreakpoint = 480;
78
80
  this._showCalendar = false;
79
81
  this._timeSelection = UNDEF;
82
+ this._useModal = false;
83
+ this._displayedMonth = /* @__PURE__ */ new Date();
84
+ /** @ignore */
80
85
  this._calendarPosition = "bottom";
81
86
  this._inputType = INPUT_TYPE_DATE;
82
87
  this._validators = [this._requiredDateTimeValidator.bind(this)];
83
88
  }
89
+ /** Time selection options with i18n placeholder. */
90
+ get _timeOptions() {
91
+ return [
92
+ {
93
+ name: msg("Uhrzeit auswählen", { id: "pd.datepicker.selectTime" }),
94
+ value: UNDEF
95
+ },
96
+ ...TIME_VALUES
97
+ ];
98
+ }
99
+ disconnectedCallback() {
100
+ super.disconnectedCallback();
101
+ if (this._boundHandleClickOutside) {
102
+ document.removeEventListener("click", this._boundHandleClickOutside);
103
+ this._boundHandleClickOutside = void 0;
104
+ }
105
+ if (this._useModal && this._showCalendar) {
106
+ document.body.style.overflow = "";
107
+ }
108
+ }
84
109
  _requiredDateTimeValidator() {
85
110
  return this.required && !this._startDateValue || this.dateRange && this._startDateValue && !this._endDateValue || this.withTime && this._startDateValue && this._timeSelection === UNDEF ? msg("Eingabe unvollständig", {
86
111
  id: "pd.form.field.selectDateTimeRequired"
@@ -89,11 +114,12 @@ let PdDatepicker = class extends PdBaseInputElement {
89
114
  update(changedProps) {
90
115
  if (changedProps.has("initialDate") && this.initialDate) {
91
116
  this._prepareFieldsFromInitDate();
92
- this._updateInputField(false, void 0);
117
+ this._updateInputField(this.handleChangeForInitVal, void 0);
93
118
  }
94
119
  super.update(changedProps);
95
120
  }
96
121
  render() {
122
+ const popupId = `${this.id || "datepicker"}-popup`;
97
123
  return html`
98
124
  <pd-input
99
125
  id="datePickerId"
@@ -105,38 +131,53 @@ let PdDatepicker = class extends PdBaseInputElement {
105
131
  ?required="${this.required}"
106
132
  ?disabled="${this.disabled}"
107
133
  icon-right
134
+ aria-haspopup="dialog"
135
+ aria-expanded="${this._showCalendar}"
136
+ aria-controls="${popupId}"
108
137
  @click="${this._inputClick}"
138
+ @keydown="${this._onInputKeyDown}"
109
139
  @pd-form-element-change="${this._innerFormChange}"
110
140
  @pd-form-element-blur="${this._innerBlur}"
111
141
  @pd-form-element-focus="${this._innerFocus}"
112
142
  @pd-form-element-register="${this._innerRegister}"
113
143
  @enter-pressed="${this._innerEnter}"
114
- >
115
- <div slot="icon-right">
116
- <slot name="icon-right"></slot>
117
- </div>
118
- ></pd-input
119
- >
144
+ ></pd-input>
120
145
  ${this._renderErrorMsg()}
121
- <div class="calendar-small ${this._calendarPosition}">
146
+ <div
147
+ class="modal-backdrop ${this._useModal ? "active" : ""}"
148
+ @click="${this._closeCalendar}"
149
+ ></div>
150
+ <div
151
+ id="${popupId}"
152
+ class="calendar-small ${this._useModal ? "modal" : this._calendarPosition}"
153
+ role="dialog"
154
+ aria-modal="true"
155
+ aria-label="${msg("Datum auswählen", {
156
+ id: "pd.datepicker.selectDate"
157
+ })}"
158
+ @keydown="${this._onPopupKeyDown}"
159
+ >
122
160
  <pd-calendar
123
161
  .withYearPopup="${this.withYearPopup}"
124
162
  .refDate="${this._startDateValue}"
125
- .data="${this._rangeSelection || {}}"
163
+ .data="${this._buildConstrainedData(this._displayedMonth)}"
126
164
  numberClass="center"
127
165
  selectableDates
128
166
  showSelection
167
+ withWheelNavigation
168
+ withTouchNavigation
129
169
  prevMonthConstraint="-1"
130
170
  nextMonthConstraint="-1"
131
171
  @select-date="${this._triggerCalendarDateSelected}"
132
172
  @mouse-enter-date="${this._triggerHoverCalculateRange}"
173
+ @change-month="${this._onCalendarMonthChange}"
133
174
  ></pd-calendar>
134
175
 
135
176
  ${this.withTime ? html`
136
177
  <pd-select
137
178
  class="date-time-select"
138
179
  id="dateTimeSelectId"
139
- .values="${DATE_TIMES}"
180
+ .values="${this._timeOptions}"
140
181
  label="${msg("Uhrzeit", { id: "pd.datepicker.time" })}"
141
182
  initValue="${this._timeSelection}"
142
183
  required
@@ -149,13 +190,13 @@ let PdDatepicker = class extends PdBaseInputElement {
149
190
  @pd-form-element-register="${this._innerRegister}"
150
191
  @enter-pressed="${this._innerEnter}"
151
192
  ></pd-select>
152
- ` : ""}
193
+ ` : nothing}
153
194
 
154
195
  <div class="bottom-buttons">
155
- ${!this.hideToday ? html`<pd-button
196
+ ${!this.hideToday && !this.dateRange ? html`<pd-button
156
197
  text="${msg("Heute", { id: "pd.datepicker.today" })}"
157
198
  @button-clicked="${this._triggerSetTodayButton}"
158
- ></pd-button>` : ""}
199
+ ></pd-button>` : nothing}
159
200
  <pd-button
160
201
  text="${msg("Reset", { id: "pd.datepicker.reset" })}"
161
202
  @button-clicked="${this._triggerResetButton}"
@@ -204,8 +245,10 @@ let PdDatepicker = class extends PdBaseInputElement {
204
245
  return this._formatDateValue();
205
246
  }
206
247
  /**
207
- * @returns parsed date
248
+ * Returns the parsed date values.
249
+ * @returns Object with start and optional end date: `{ start?: Date; end?: Date }`
208
250
  */
251
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
209
252
  _getParsedValue() {
210
253
  return this.dateValues;
211
254
  }
@@ -246,21 +289,104 @@ let PdDatepicker = class extends PdBaseInputElement {
246
289
  );
247
290
  }
248
291
  /**
249
- * Toogle view calendar on click into pd-input field.
292
+ * Toggle view calendar on click into pd-input field.
250
293
  */
251
294
  _inputClick() {
252
- const input = this.shadowRoot?.getElementById("datePickerId");
253
- if (input) {
254
- const rect = input.getBoundingClientRect();
255
- const spaceBelow = window.innerHeight - rect.bottom;
256
- const spaceAbove = rect.top;
257
- this._calendarPosition = spaceBelow < 300 && spaceAbove > spaceBelow ? "top" : "bottom";
258
- this._showCalendar = !this._showCalendar;
295
+ if (this._showCalendar) {
296
+ this._closeCalendar();
297
+ } else {
298
+ this._openCalendar();
299
+ }
300
+ }
301
+ /**
302
+ * Handle keyboard events on the input field.
303
+ * Enter toggles calendar, Space/ArrowDown opens, Escape closes.
304
+ */
305
+ _onInputKeyDown(e) {
306
+ switch (e.key) {
307
+ case " ":
308
+ case "Enter":
309
+ e.preventDefault();
310
+ if (this._showCalendar) {
311
+ this._closeCalendar();
312
+ } else {
313
+ this._openCalendar();
314
+ }
315
+ break;
316
+ case "ArrowDown":
317
+ e.preventDefault();
318
+ if (!this._showCalendar) this._openCalendar();
319
+ break;
320
+ case "Escape":
321
+ if (this._showCalendar) {
322
+ e.preventDefault();
323
+ this._closeCalendar();
324
+ }
325
+ break;
326
+ }
327
+ }
328
+ /**
329
+ * Handle keyboard events within the popup.
330
+ */
331
+ _onPopupKeyDown(e) {
332
+ if (e.key === "Escape") {
333
+ e.preventDefault();
334
+ e.stopPropagation();
335
+ this._closeCalendar();
336
+ }
337
+ }
338
+ /**
339
+ * Open the calendar popup.
340
+ */
341
+ _openCalendar() {
342
+ this._displayedMonth = this._startDateValue || /* @__PURE__ */ new Date();
343
+ this._useModal = this.modal || window.innerWidth < this.modalBreakpoint;
344
+ if (!this._useModal) {
345
+ const input = this.shadowRoot?.getElementById("datePickerId");
346
+ if (input) {
347
+ const rect = input.getBoundingClientRect();
348
+ const spaceBelow = window.innerHeight - rect.bottom;
349
+ const spaceAbove = rect.top;
350
+ this._calendarPosition = spaceBelow < 380 && spaceAbove > spaceBelow ? "top" : "bottom";
351
+ }
352
+ }
353
+ if (this._useModal) {
354
+ document.body.style.overflow = "hidden";
355
+ }
356
+ this._showCalendar = true;
357
+ if (!this._useModal) {
259
358
  setTimeout(() => {
260
- this.shadowRoot?.querySelector(".calendar-small")?.scrollIntoView({ behavior: "smooth", block: "nearest" });
359
+ this._boundHandleClickOutside = this._handleClickOutside.bind(this);
360
+ document.addEventListener("click", this._boundHandleClickOutside);
261
361
  }, 0);
262
362
  }
263
363
  }
364
+ /**
365
+ * Close the calendar popup and return focus to input.
366
+ */
367
+ _closeCalendar() {
368
+ this._showCalendar = false;
369
+ if (this._useModal) {
370
+ document.body.style.overflow = "";
371
+ }
372
+ if (this._boundHandleClickOutside) {
373
+ document.removeEventListener("click", this._boundHandleClickOutside);
374
+ this._boundHandleClickOutside = void 0;
375
+ }
376
+ const input = this.shadowRoot?.getElementById(
377
+ "datePickerId"
378
+ );
379
+ input?.focus();
380
+ }
381
+ /**
382
+ * Handle clicks outside the popup.
383
+ */
384
+ _handleClickOutside(e) {
385
+ const path = e.composedPath();
386
+ if (!path.includes(this)) {
387
+ this._closeCalendar();
388
+ }
389
+ }
264
390
  /**
265
391
  * Triggered by date selection in small calendar.
266
392
  * Set internal values depending on daterange configuration.
@@ -280,7 +406,7 @@ let PdDatepicker = class extends PdBaseInputElement {
280
406
  } else {
281
407
  this._endDateValue = date;
282
408
  }
283
- this._showCalendar = false;
409
+ this._closeCalendar();
284
410
  } else {
285
411
  this._startDateValue = date;
286
412
  this._endDateValue = void 0;
@@ -293,7 +419,7 @@ let PdDatepicker = class extends PdBaseInputElement {
293
419
  );
294
420
  el?.focus();
295
421
  } else {
296
- this._showCalendar = false;
422
+ this._closeCalendar();
297
423
  }
298
424
  }
299
425
  if (!this._showCalendar) {
@@ -310,8 +436,11 @@ let PdDatepicker = class extends PdBaseInputElement {
310
436
  if (this.dateRange) {
311
437
  this._endDateValue = void 0;
312
438
  this._rangeSelection = void 0;
313
- } else {
314
- this._showCalendar = this.withTime;
439
+ } else if (!this.withTime) {
440
+ this._closeCalendar();
441
+ this._updateInputField(true, e);
442
+ e.stopPropagation();
443
+ return;
315
444
  }
316
445
  this._updateInputField(!this._showCalendar, e);
317
446
  e.stopPropagation();
@@ -322,8 +451,7 @@ let PdDatepicker = class extends PdBaseInputElement {
322
451
  */
323
452
  _triggerResetButton(e) {
324
453
  this.reset();
325
- this._showCalendar = false;
326
- this.shadowRoot?.getElementById("datePickerId")?.reset();
454
+ this._closeCalendar();
327
455
  e.stopPropagation();
328
456
  }
329
457
  /**
@@ -332,7 +460,17 @@ let PdDatepicker = class extends PdBaseInputElement {
332
460
  */
333
461
  _triggerSetValueButton(e) {
334
462
  this._updateInputField(true, e);
335
- this._showCalendar = false;
463
+ this._closeCalendar();
464
+ e.stopPropagation();
465
+ }
466
+ /**
467
+ * Handle month change from calendar navigation.
468
+ * Updates _displayedMonth to recalculate constraints for the new month.
469
+ */
470
+ _onCalendarMonthChange(e) {
471
+ if (e.detail.newDate) {
472
+ this._displayedMonth = e.detail.newDate;
473
+ }
336
474
  e.stopPropagation();
337
475
  }
338
476
  /**
@@ -368,6 +506,29 @@ let PdDatepicker = class extends PdBaseInputElement {
368
506
  this.dateFormat
369
507
  );
370
508
  }
509
+ /**
510
+ * Builds calendar data with disabled days based on min/max constraints and disabledDays.
511
+ * Merges with existing range selection data.
512
+ */
513
+ _buildConstrainedData(currentMonth) {
514
+ const result = { ...this._rangeSelection || {} };
515
+ const minDate = this.min ? parse(this.min, DEFAULT_FORMAT, /* @__PURE__ */ new Date()) : null;
516
+ const maxDate = this.max ? parse(this.max, DEFAULT_FORMAT, /* @__PURE__ */ new Date()) : null;
517
+ const year = currentMonth.getFullYear();
518
+ const month = currentMonth.getMonth();
519
+ const firstDay = new Date(year, month, 1);
520
+ const lastDay = new Date(year, month + 1, 0);
521
+ for (let day = new Date(firstDay); day <= lastDay; day.setDate(day.getDate() + 1)) {
522
+ const key = format(day, DEFAULT_FORMAT);
523
+ const isBeforeMin = minDate && day < minDate;
524
+ const isAfterMax = maxDate && day > maxDate;
525
+ const isInDisabledDays = this.disabledDays.includes(key);
526
+ if (isBeforeMin || isAfterMax || isInDisabledDays) {
527
+ result[key] = [{ ...result[key]?.[0], disabled: true }];
528
+ }
529
+ }
530
+ return result;
531
+ }
371
532
  // ###### Start Inner Element Events
372
533
  _innerEnter(e) {
373
534
  e.stopPropagation();
@@ -393,6 +554,7 @@ PdDatepicker.styles = [
393
554
  css`
394
555
  :host {
395
556
  position: relative;
557
+ display: inline-block;
396
558
  }
397
559
 
398
560
  :host([disabled]) {
@@ -406,26 +568,18 @@ PdDatepicker.styles = [
406
568
 
407
569
  .calendar-small {
408
570
  position: absolute;
409
- background-color: white;
571
+ background-color: var(--pd-default-bg-col);
410
572
  visibility: hidden;
411
- z-index: 1000;
412
- box-shadow: var(--pd-menu-shadow, 3px 3px 5px grey);
573
+ z-index: var(--pd-datepicker-z-index, 1000);
574
+ box-shadow: var(--pd-menu-shadow, var(--pd-shadow-lg));
413
575
  transition: 0.5s ease-out;
414
576
  transform: translateY(0);
415
577
  opacity: 0;
416
- padding: 0.5em 1em 0.5em 0.2em;
417
-
418
- --pd-calendar-width: var(--pd-input-field-width, 250px);
419
- --pd-calendar-cell-height: 30px;
420
- --pd-calendar-week-title-bg-col: white;
421
- --pd-calendar-week-title-font-col: #0a3a48;
578
+ padding: 0.5em;
579
+ max-width: 400px;
422
580
  --pd-calendar-cell-selectable-shadow: 0;
423
- --pd-calendar-cell-day-free-bg-col: white;
424
- --pd-calendar-cell-day-info-free-col: #0a3a48;
425
- --pd-calendar-title-font-size: 20px;
426
- --pd-calendar-title-icon-size: 20px;
427
- --pd-calendar-weekday-title-font-size: 15px;
428
- --pd-calendar-number-font-size: 15px;
581
+ --pd-calendar-cell-day-free-bg-col: var(--pd-default-bg-col);
582
+ --pd-calendar-cell-day-info-free-col: var(--pd-default-font-title-col);
429
583
  }
430
584
 
431
585
  .calendar-small.bottom {
@@ -436,9 +590,47 @@ PdDatepicker.styles = [
436
590
  bottom: 100%; /* Über dem Input-Feld */
437
591
  }
438
592
 
593
+ .date-time-select {
594
+ display: block;
595
+ --pd-input-field-height: 32px;
596
+ margin-top: var(--pd-spacing-sm);
597
+ }
598
+
439
599
  .bottom-buttons {
440
600
  display: flex;
441
- --pd-button-width: 78px;
601
+ --pd-button-min-height: 32px;
602
+ --pd-button-height: 32px;
603
+ --pd-button-scale: 0.9;
604
+ gap: var(--pd-spacing-sm);
605
+ margin-top: var(--pd-spacing-sm);
606
+ }
607
+
608
+ /* Modal backdrop overlay */
609
+ .modal-backdrop {
610
+ display: none;
611
+ position: fixed;
612
+ inset: 0;
613
+ background-color: var(--pd-modal-overlay-col, rgba(0, 0, 0, 0.5));
614
+ z-index: calc(var(--pd-datepicker-z-index, 1000) - 1);
615
+ }
616
+
617
+ :host([_showCalendar]) .modal-backdrop.active {
618
+ display: block;
619
+ }
620
+
621
+ /* Modal mode: centered calendar, slightly above center for mobile usability */
622
+ .calendar-small.modal {
623
+ position: fixed;
624
+ top: 40%;
625
+ left: 50%;
626
+ transform: translate(-50%, -50%);
627
+ margin: 0;
628
+ padding: var(--pd-spacing-md);
629
+ border-radius: var(--pd-radius-lg);
630
+ max-height: 90vh;
631
+ min-height: 360px; /* Prevent jumping between months with different week counts */
632
+ overflow-y: auto;
633
+ width: calc(100vw - 2rem); /* 1rem Abstand links + rechts */
442
634
  }
443
635
  `
444
636
  ];
@@ -472,6 +664,15 @@ __decorateClass([
472
664
  __decorateClass([
473
665
  property({ type: String })
474
666
  ], PdDatepicker.prototype, "max", 2);
667
+ __decorateClass([
668
+ property({ type: Array })
669
+ ], PdDatepicker.prototype, "disabledDays", 2);
670
+ __decorateClass([
671
+ property({ type: Boolean })
672
+ ], PdDatepicker.prototype, "modal", 2);
673
+ __decorateClass([
674
+ property({ type: Number })
675
+ ], PdDatepicker.prototype, "modalBreakpoint", 2);
475
676
  __decorateClass([
476
677
  property({ type: Boolean, reflect: true })
477
678
  ], PdDatepicker.prototype, "_showCalendar", 2);
@@ -487,6 +688,12 @@ __decorateClass([
487
688
  __decorateClass([
488
689
  state()
489
690
  ], PdDatepicker.prototype, "_timeSelection", 2);
691
+ __decorateClass([
692
+ state()
693
+ ], PdDatepicker.prototype, "_useModal", 2);
694
+ __decorateClass([
695
+ state()
696
+ ], PdDatepicker.prototype, "_displayedMonth", 2);
490
697
  PdDatepicker = __decorateClass([
491
698
  localized()
492
699
  ], PdDatepicker);
@@ -1,23 +1,81 @@
1
- import { StoryObj } from '@storybook/web-components';
2
- declare const meta: {
3
- title: string;
4
- tags: string[];
5
- render: (args: import('@storybook/web-components').Args) => import('lit').TemplateResult<1>;
6
- argTypes: {};
7
- };
1
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
2
+ /**
3
+ * Story arguments interface for pd-datepicker component.
4
+ * Maps to the component's public API.
5
+ */
6
+ interface PdDatepickerArgs {
7
+ /** Field label */
8
+ label: string;
9
+ /** Placeholder text */
10
+ placeholder: string;
11
+ /** Whether the field is required */
12
+ required: boolean;
13
+ /** Whether the field is disabled */
14
+ disabled: boolean;
15
+ /** Whether to show time selection */
16
+ withTime: boolean;
17
+ /** Whether to enable date range selection */
18
+ dateRange: boolean;
19
+ /** Initial date value */
20
+ initialDate?: Date;
21
+ /** Date format string */
22
+ dateFormat: string;
23
+ /** Minimum allowed date (YYYY-MM-DD) */
24
+ min?: string;
25
+ /** Maximum allowed date (YYYY-MM-DD) */
26
+ max?: string;
27
+ /** Year selection popup values */
28
+ withYearPopup: string[];
29
+ /** Whether to hide today button */
30
+ hideToday: boolean;
31
+ }
32
+ /**
33
+ * ## pd-datepicker
34
+ *
35
+ * A datepicker component for selecting dates with optional time and range support.
36
+ * Opens a calendar popup on click and integrates seamlessly with pd-form-container
37
+ * for validation.
38
+ *
39
+ * ### Features
40
+ * - **Date Selection**: Click to open calendar popup for date selection
41
+ * - **Time Selection**: Optional time picker with predefined time slots
42
+ * - **Date Range**: Optional range selection for start and end dates
43
+ * - **Year Popup**: Quick year navigation via dropdown
44
+ * - **Min/Max Constraints**: Limit selectable date range with `min` and `max` properties
45
+ * - **Disabled Days**: Disable specific dates via `disabledDays` array
46
+ * - **Modal Mode**: Centered modal display for mobile devices (auto or forced)
47
+ * - **Form Integration**: Works with pd-form-container for validation
48
+ * - **Popup Positioning**: Automatically opens above or below based on viewport space
49
+ *
50
+ * ### Accessibility
51
+ * - `aria-haspopup="dialog"` on the input field
52
+ * - `aria-expanded` reflects popup open/close state
53
+ * - `aria-controls` links input to popup
54
+ * - `aria-modal="true"` on the calendar popup
55
+ * - Keyboard: Enter/Space toggles popup, ArrowDown opens, Escape closes
56
+ * - Focus returns to input when popup closes
57
+ */
58
+ declare const meta: Meta<PdDatepickerArgs>;
8
59
  export default meta;
9
- type Story = StoryObj;
10
- export declare const Standard: Story;
11
- export declare const PlaceholderLabel: Story;
12
- export declare const Locale: Story;
13
- export declare const Required: Story;
14
- export declare const YearSelection: Story;
15
- export declare const HugeYearSelection: Story;
16
- export declare const Disabled: Story;
60
+ type Story = StoryObj<PdDatepickerArgs>;
61
+ /** Default datepicker. Interactive via Controls panel. */
62
+ export declare const Default: Story;
63
+ /** All datepicker configurations at a glance. */
64
+ export declare const AllVariants: Story;
65
+ /** Datepicker with time selection -- date + time picker combination. */
17
66
  export declare const WithTime: Story;
18
- export declare const WithRange: Story;
19
- export declare const InitialValue: Story;
20
- export declare const MinMax: Story;
21
- export declare const DatepickerInForm: Story;
22
- export declare const DatepickerInFormWithInit: Story;
67
+ /** Datepicker for selecting a start and end date. */
68
+ export declare const DateRange: Story;
69
+ /** Different date format locales side by side. */
70
+ export declare const Locales: Story;
71
+ /** Date constraints with min/max properties, disabled days, and linked datepickers. */
72
+ export declare const MinMaxDate: Story;
73
+ /** Modal mode displays the calendar centered on screen with a backdrop overlay. */
74
+ export declare const ModalMode: Story;
75
+ /** Datepicker within a pd-form-container with validation. */
76
+ export declare const InForm: Story;
77
+ /** Tests automatic popup positioning based on available viewport space. */
78
+ export declare const PopupPosition: Story;
79
+ /** CSS Custom Properties -- Branded and Redesigned datepicker variants. */
80
+ export declare const CustomStyling: Story;
23
81
  //# sourceMappingURL=pd-date-picker.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pd-date-picker.stories.d.ts","sourceRoot":"","sources":["../../src/pd-datepicker/pd-date-picker.stories.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAMhE,OAAO,qDAAqD,CAAC;AAC7D,OAAO,+CAA+C,CAAC;AACvD,OAAO,6CAA6C,CAAC;AAErD,OAAO,oBAAoB,CAAC;AAG5B,QAAA,MAAM,IAAI;;;;;CAkBM,CAAC;AAEjB,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAEtB,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAK9B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAiBpB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAS3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAS/B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAMtB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAKF,eAAO,MAAM,YAAY,EAAE,KAe1B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAcpB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KA+F9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,KA2ItC,CAAC"}
1
+ {"version":3,"file":"pd-date-picker.stories.d.ts","sourceRoot":"","sources":["../../src/pd-datepicker/pd-date-picker.stories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAKrE,OAAO,qDAAqD,CAAC;AAC7D,OAAO,+CAA+C,CAAC;AACvD,OAAO,6CAA6C,CAAC;AAErD,OAAO,oBAAoB,CAAC;AAM5B;;;GAGG;AACH,UAAU,gBAAgB;IACxB,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,qCAAqC;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,yBAAyB;IACzB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mCAAmC;IACnC,SAAS,EAAE,OAAO,CAAC;CACpB;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAoFhC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAMxC,0DAA0D;AAC1D,eAAO,MAAM,OAAO,EAAE,KAcrB,CAAC;AAMF,iDAAiD;AACjD,eAAO,MAAM,WAAW,EAAE,KAuEzB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,QAAQ,EAAE,KA+BtB,CAAC;AAMF,qDAAqD;AACrD,eAAO,MAAM,SAAS,EAAE,KA4BvB,CAAC;AAMF,kDAAkD;AAClD,eAAO,MAAM,OAAO,EAAE,KA4CrB,CAAC;AAMF,uFAAuF;AACvF,eAAO,MAAM,UAAU,EAAE,KAqGxB,CAAC;AAMF,mFAAmF;AACnF,eAAO,MAAM,SAAS,EAAE,KA8DvB,CAAC;AAMF,6DAA6D;AAC7D,eAAO,MAAM,MAAM,EAAE,KA0EpB,CAAC;AAMF,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,KAoC3B,CAAC;AAMF,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,KA4G3B,CAAC"}