@dereekb/dbx-form 13.4.0 → 13.4.2

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.
@@ -15,8 +15,7 @@ import * as i1$1 from '@dereekb/dbx-core';
15
15
  import { TimezoneAbbreviationPipe, switchMapDbxInjectionComponentConfig, DbxInjectionComponent } from '@dereekb/dbx-core';
16
16
  import { toSignal, toObservable } from '@angular/core/rxjs-interop';
17
17
  import { MatDialog } from '@angular/material/dialog';
18
- import * as i1$5 from 'angular-calendar';
19
- import { CalendarModule } from 'angular-calendar';
18
+ import { CalendarMonthViewComponent, CalendarDatePipe } from 'angular-calendar';
20
19
  import { DbxCalendarStore, prepareAndSortCalendarEvents, DbxCalendarBaseComponent } from '@dereekb/dbx-web/calendar';
21
20
  import * as i2 from '@angular/forms';
22
21
  import { FormGroup, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
@@ -27,9 +26,15 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
27
26
  import { NgClass } from '@angular/common';
28
27
  import * as i1$4 from '@angular/material/icon';
29
28
  import { MatIconModule } from '@angular/material/icon';
30
- import * as i1$6 from '@ngx-formly/core';
29
+ import * as i1$5 from '@ngx-formly/core';
31
30
  import { FormlyModule } from '@ngx-formly/core';
32
31
 
32
+ /**
33
+ * Creates a Formly field configuration for a date schedule range picker with calendar-based selection.
34
+ *
35
+ * @param config - Optional schedule range field configuration overrides
36
+ * @returns A validated Formly field configuration for date schedule range selection
37
+ */
33
38
  function dateScheduleRangeField(config = {}) {
34
39
  const { key = 'schedule', appearance, hideCustomize, allowTextInput, filter, outputTimezone, initialSelectionState, computeSelectionResultRelativeToFilter, exclusions, defaultScheduleDays, minMaxDateRange, cellContentFactory, dialogContentConfig, customDetailsConfig } = config;
35
40
  const fieldConfig = {
@@ -80,6 +85,9 @@ const defaultCalendarScheduleSelectionCellContentFactory = (day) => {
80
85
  icon = 'check_box_outline_blank';
81
86
  text = 'Add';
82
87
  break;
88
+ default:
89
+ // meta.state is undefined when no metadata is attached to the day cell
90
+ break;
83
91
  }
84
92
  const result = {
85
93
  icon,
@@ -88,6 +96,12 @@ const defaultCalendarScheduleSelectionCellContentFactory = (day) => {
88
96
  return result;
89
97
  };
90
98
 
99
+ /**
100
+ * Creates the default initial state for the calendar schedule selection store,
101
+ * using the current system timezone and all days of the week enabled.
102
+ *
103
+ * @returns A fresh CalendarScheduleSelectionState with default values
104
+ */
91
105
  function initialCalendarScheduleSelectionState() {
92
106
  const defaultScheduleDays = new Set([DateCellScheduleDayCode.WEEKDAY, DateCellScheduleDayCode.WEEKEND]);
93
107
  const allowedDaysOfWeek = expandDateCellScheduleDayCodesToDayOfWeekSet(defaultScheduleDays);
@@ -134,18 +148,42 @@ function calendarScheduleMinAndMaxDateRangeRelativeToFilter(x) {
134
148
  }
135
149
  return calendarScheduleMinAndMaxDateRange(input);
136
150
  }
151
+ /**
152
+ * Computes the effective min and max date range by combining the filter and the explicit minMaxDateRange constraints.
153
+ *
154
+ * @param x - State containing filter and minMaxDateRange to compute from
155
+ * @returns A partial date range with the effective start and end boundaries
156
+ */
137
157
  function calendarScheduleMinAndMaxDateRange(x) {
138
158
  return {
139
159
  start: calendarScheduleMinDate(x) || undefined,
140
160
  end: calendarScheduleMaxDate(x) || undefined
141
161
  };
142
162
  }
163
+ /**
164
+ * Returns the effective minimum date by taking the latest start date between the filter and minMaxDateRange.
165
+ *
166
+ * @param x - State containing filter and minMaxDateRange
167
+ * @returns The latest start date, or undefined if none
168
+ */
143
169
  function calendarScheduleMinDate(x) {
144
170
  return findMaxDate([x.filter?.start, x.minMaxDateRange?.start]);
145
171
  }
172
+ /**
173
+ * Returns the effective maximum date by taking the earliest end date between the filter and minMaxDateRange.
174
+ *
175
+ * @param x - State containing filter and minMaxDateRange
176
+ * @returns The earliest end date, or undefined if none
177
+ */
146
178
  function calendarScheduleMaxDate(x) {
147
179
  return findMinDate([x.filter?.end, x.minMaxDateRange?.end]);
148
180
  }
181
+ /**
182
+ * Returns whether the filter's start date is being used as the effective start for the selection result computation.
183
+ *
184
+ * @param x - State containing filter and computeSelectionResultRelativeToFilter
185
+ * @returns True if the filter start is being used for the selection result
186
+ */
149
187
  function calendarScheduleStartBeingUsedFromFilter(x) {
150
188
  return x.computeSelectionResultRelativeToFilter && x.filter?.start != null; // may be using either
151
189
  }
@@ -165,7 +203,7 @@ class DbxCalendarScheduleSelectionStore extends ComponentStore {
165
203
  minMaxDateRange$ = this.state$.pipe(map(calendarScheduleMinAndMaxDateRange), distinctUntilChanged(isSameDateRange), shareReplay(1));
166
204
  minDate$ = this.minMaxDateRange$.pipe(map((x) => x?.start), distinctUntilChanged(isSameDateDay), shareReplay(1));
167
205
  maxDate$ = this.minMaxDateRange$.pipe(map((x) => x?.end), distinctUntilChanged(isSameDateDay), shareReplay(1));
168
- hasConfiguredMinMaxRange$ = this.minMaxDateRange$.pipe(map((x) => x != null && x.start != null && x.end != null), distinctUntilChanged(), shareReplay(1));
206
+ hasConfiguredMinMaxRange$ = this.minMaxDateRange$.pipe(map((x) => x?.start != null && x.end != null), distinctUntilChanged(), shareReplay(1));
169
207
  inputStart$ = this.state$.pipe(map((x) => x.inputStart), distinctUntilChanged(isSameDate), shareReplay(1));
170
208
  inputEnd$ = this.state$.pipe(map((x) => x.inputEnd), distinctUntilChanged(isSameDate), shareReplay(1));
171
209
  currentInputRange$ = this.state$.pipe(map(({ inputStart, inputEnd }) => ({ start: inputStart, end: inputEnd })), distinctUntilChanged((a, b) => isSameDateRange(a, b)), map((x) => ({ inputStart: x.start, inputEnd: x.end })), map((x) => {
@@ -279,6 +317,13 @@ class DbxCalendarScheduleSelectionStore extends ComponentStore {
279
317
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxCalendarScheduleSelectionStore, decorators: [{
280
318
  type: Injectable
281
319
  }], ctorParameters: () => [] });
320
+ /**
321
+ * Updates the state with an initial selection (all or none) and applies it when no dates are currently toggled.
322
+ *
323
+ * @param state - The current selection state
324
+ * @param initialSelectionState - The initial selection mode ('all' or 'none')
325
+ * @returns The updated selection state
326
+ */
282
327
  function updateStateWithInitialSelectionState(state, initialSelectionState) {
283
328
  const { toggledIndexes } = state;
284
329
  if (toggledIndexes.size === 0 && initialSelectionState === 'all') {
@@ -286,6 +331,13 @@ function updateStateWithInitialSelectionState(state, initialSelectionState) {
286
331
  }
287
332
  return { ...state, initialSelectionState };
288
333
  }
334
+ /**
335
+ * Updates the computeSelectionResultRelativeToFilter flag and recalculates the state if the value changed.
336
+ *
337
+ * @param currentState - The current selection state
338
+ * @param computeSelectionResultRelativeToFilter - Whether to compute results relative to the filter
339
+ * @returns The updated selection state
340
+ */
289
341
  function updateStateWithComputeSelectionResultRelativeToFilter(currentState, computeSelectionResultRelativeToFilter) {
290
342
  let state = { ...currentState, computeSelectionResultRelativeToFilter };
291
343
  if (Boolean(currentState.computeSelectionResultRelativeToFilter) !== Boolean(computeSelectionResultRelativeToFilter)) {
@@ -293,6 +345,13 @@ function updateStateWithComputeSelectionResultRelativeToFilter(currentState, com
293
345
  }
294
346
  return state;
295
347
  }
348
+ /**
349
+ * Updates the state with date exclusions, converting input dates/ranges to cell indexes and reapplying the filter.
350
+ *
351
+ * @param state - The current selection state
352
+ * @param inputExclusions - Dates, date ranges, or cell indexes to exclude
353
+ * @returns The updated selection state with exclusions applied
354
+ */
296
355
  function updateStateWithExclusions(state, inputExclusions) {
297
356
  let computedExclusions;
298
357
  if (inputExclusions) {
@@ -303,6 +362,13 @@ function updateStateWithExclusions(state, inputExclusions) {
303
362
  state = { ...state, inputExclusions, computedExclusions };
304
363
  return updateStateWithFilter(state, state.filter);
305
364
  }
365
+ /**
366
+ * Sets the min/max date range constraint on the state, normalizing start to startOfDay and end to endOfDay.
367
+ *
368
+ * @param state - The current selection state
369
+ * @param minMaxDateRange - The min/max boundary dates to enforce
370
+ * @returns The updated selection state with the boundary applied
371
+ */
306
372
  function updateStateWithMinMaxDateRange(state, minMaxDateRange) {
307
373
  if (minMaxDateRange != null && !isInfiniteDateRange(minMaxDateRange)) {
308
374
  state = {
@@ -318,6 +384,23 @@ function updateStateWithMinMaxDateRange(state, minMaxDateRange) {
318
384
  }
319
385
  return updateStateWithFilter(state, state.filter);
320
386
  }
387
+ /**
388
+ * Applies a date cell schedule filter to the selection state, computing the enabled day function
389
+ * from the filter, exclusions, and min/max date range constraints.
390
+ *
391
+ * @param currentState - The current selection state
392
+ * @param inputFilter - The filter configuration to apply
393
+ * @returns The updated selection state with the filter applied
394
+ */
395
+ /**
396
+ * Applies a date cell schedule filter to the selection state, computing the enabled day function
397
+ * from the filter, exclusions, and min/max date range constraints.
398
+ *
399
+ * @param currentState - The current selection state
400
+ * @param inputFilter - The filter configuration to apply
401
+ * @returns The updated selection state with the filter applied
402
+ */
403
+ // eslint-disable-next-line sonarjs/cognitive-complexity
321
404
  function updateStateWithFilter(currentState, inputFilter) {
322
405
  const { computedExclusions: exclusions, minMaxDateRange, systemTimezone } = currentState;
323
406
  let isEnabledFilterDay = () => true;
@@ -412,7 +495,7 @@ function updateStateWithFilter(currentState, inputFilter) {
412
495
  }
413
496
  let nextState = { ...currentState, filter, isEnabledFilterDay };
414
497
  // For the same reason as above, use the filter's start date as the relative start if applicable.
415
- if (filter && filter.start) {
498
+ if (filter?.start) {
416
499
  let startForSystemTimezone = filter.start;
417
500
  if (filter.timezone) {
418
501
  const timezoneNormal = dateTimezoneUtcNormal(filter.timezone);
@@ -433,6 +516,13 @@ function updateStateWithFilter(currentState, inputFilter) {
433
516
  }
434
517
  return nextState;
435
518
  }
519
+ /**
520
+ * Updates the output timezone and transforms the current selection value to reflect the new timezone.
521
+ *
522
+ * @param state - The current selection state
523
+ * @param timezone - The target timezone string
524
+ * @returns The updated selection state with timezone-adjusted values
525
+ */
436
526
  function updateStateWithTimezoneValue(state, timezone) {
437
527
  const { currentSelectionValue } = state;
438
528
  const timezoneNormal = timezone ? dateTimezoneUtcNormal({ timezone }) : undefined;
@@ -452,6 +542,14 @@ function updateStateWithTimezoneValue(state, timezone) {
452
542
  return { ...state, outputTimezone: timezone, outputTimezoneNormal: timezoneNormal }; // no change in value
453
543
  }
454
544
  }
545
+ /**
546
+ * Updates the state from an external date cell schedule range value, converting timezone-aware inputs
547
+ * to system time and synchronizing the internal selection indexes.
548
+ *
549
+ * @param state - The current selection state
550
+ * @param inputChange - The date cell schedule range to apply
551
+ * @returns The updated selection state
552
+ */
455
553
  function updateStateWithDateCellScheduleRangeValue(state, inputChange) {
456
554
  const { currentSelectionValue, systemTimezone } = state;
457
555
  const currentDateCellScheduleRange = currentSelectionValue?.dateScheduleRange; // current range is always in system time
@@ -492,6 +590,13 @@ function updateStateWithDateCellScheduleRangeValue(state, inputChange) {
492
590
  }
493
591
  }
494
592
  }
593
+ /**
594
+ * Updates the default schedule day codes (used when no explicit schedule days are set) and recalculates allowed days.
595
+ *
596
+ * @param state - The current selection state
597
+ * @param change - The new default schedule day codes
598
+ * @returns The updated selection state
599
+ */
495
600
  function updateStateWithChangedDefaultScheduleDays(state, change) {
496
601
  const { defaultScheduleDays: currentDefaultScheduleDays } = state;
497
602
  const defaultScheduleDays = new Set(change ?? fullWeekDateCellScheduleDayCodes());
@@ -502,6 +607,13 @@ function updateStateWithChangedDefaultScheduleDays(state, change) {
502
607
  return finalizeUpdateStateWithChangedScheduleDays(state, { ...state, defaultScheduleDays });
503
608
  }
504
609
  }
610
+ /**
611
+ * Updates the explicit schedule day codes override and recalculates allowed days of the week.
612
+ *
613
+ * @param state - The current selection state
614
+ * @param change - The new schedule day codes, or null/undefined to clear the override
615
+ * @returns The updated selection state
616
+ */
505
617
  function updateStateWithChangedScheduleDays(state, change) {
506
618
  const { scheduleDays: currentScheduleDays } = state;
507
619
  const scheduleDays = new Set(change ?? []);
@@ -524,6 +636,13 @@ function updateStateWithChangedScheduleDays(state, change) {
524
636
  return finalizeUpdateStateWithChangedScheduleDays(state, { ...state, scheduleDays: newScheduleDays ?? undefined });
525
637
  }
526
638
  }
639
+ /**
640
+ * Switches between single and multiple selection mode, trimming the selection to a single value when switching to single mode.
641
+ *
642
+ * @param state - The current selection state
643
+ * @param selectionMode - The new selection mode
644
+ * @returns The updated selection state
645
+ */
527
646
  function updateStateWithSelectionMode(state, selectionMode) {
528
647
  const { selectionMode: currentSelectionMode } = state;
529
648
  if (currentSelectionMode !== selectionMode) {
@@ -540,6 +659,13 @@ function updateStateWithSelectionMode(state, selectionMode) {
540
659
  return state;
541
660
  }
542
661
  }
662
+ /**
663
+ * Finalizes a schedule days change by recalculating allowed days of the week and updating toggled indexes accordingly.
664
+ *
665
+ * @param previousState - The state before the schedule days change
666
+ * @param nextState - The state with updated schedule day codes
667
+ * @returns The finalized selection state with recalculated allowed days and toggled indexes
668
+ */
543
669
  function finalizeUpdateStateWithChangedScheduleDays(previousState, nextState) {
544
670
  const previousScheduleDays = previousState.effectiveScheduleDays;
545
671
  const nextScheduleDays = nextState.scheduleDays ?? nextState.defaultScheduleDays;
@@ -557,8 +683,25 @@ function finalizeUpdateStateWithChangedScheduleDays(previousState, nextState) {
557
683
  });
558
684
  }
559
685
  }
686
+ /**
687
+ * Applies date changes (toggle, add, remove, set, selectAll, or reset) to the calendar selection state,
688
+ * updating toggled indexes and input start/end accordingly.
689
+ *
690
+ * @param state - The current selection state
691
+ * @param change - The date changes to apply
692
+ * @returns The updated selection state
693
+ */
694
+ /**
695
+ * Applies date changes (toggle, add, remove, set, selectAll, or reset) to the calendar selection state,
696
+ * updating toggled indexes and input start/end accordingly.
697
+ *
698
+ * @param state - The current selection state
699
+ * @param change - The date changes to apply
700
+ * @returns The updated selection state
701
+ */
702
+ // eslint-disable-next-line sonarjs/cognitive-complexity
560
703
  function updateStateWithChangedDates(state, change) {
561
- const { selectionMode, allowedDaysOfWeek, indexFactory, indexDayOfWeek, inputStart: currentInputStart, inputEnd: currentInputEnd, minMaxDateRange, filter } = state;
704
+ const { selectionMode, allowedDaysOfWeek, indexFactory, indexDayOfWeek, inputStart: currentInputStart, inputEnd: currentInputEnd, minMaxDateRange: _minMaxDateRange, filter: _filter } = state;
562
705
  const { start: minDateFromFilter, end: maxDateFromFilter } = calendarScheduleMinAndMaxDateRangeRelativeToFilter(state);
563
706
  let inputStart = currentInputStart;
564
707
  let inputEnd = currentInputEnd;
@@ -612,6 +755,9 @@ function updateStateWithChangedDates(state, change) {
612
755
  inputEnd = null;
613
756
  set = [];
614
757
  break;
758
+ default:
759
+ // selectAll is undefined or null; no bulk selection change needed
760
+ break;
615
761
  }
616
762
  const inputSetIndexes = asIndexes(set);
617
763
  toggledIndexes = new Set(inputSetIndexes);
@@ -691,9 +837,22 @@ function updateStateWithChangedDates(state, change) {
691
837
  return noSelectionCalendarScheduleSelectionState(nextState);
692
838
  }
693
839
  }
840
+ /**
841
+ * Clears all date selections from the state, retaining other configuration like schedule days and filter.
842
+ *
843
+ * @param state - The current selection state
844
+ * @returns The state with all selections cleared
845
+ */
694
846
  function noSelectionCalendarScheduleSelectionState(state) {
695
847
  return finalizeNewCalendarScheduleSelectionState({ ...state, toggledIndexes: new Set(), inputStart: null, inputEnd: null });
696
848
  }
849
+ /**
850
+ * Updates the selection state with a new start/end date range, retaining toggled indexes within the new range bounds.
851
+ *
852
+ * @param state - The current selection state
853
+ * @param change - The new input start and end dates
854
+ * @returns The updated selection state
855
+ */
697
856
  function updateStateWithChangedRange(state, change) {
698
857
  const { inputStart: currentInputStart, inputEnd: currentInputEnd, indexFactory } = state;
699
858
  const { start: minDate, end: maxDate } = calendarScheduleMinAndMaxDateRange(state);
@@ -706,18 +865,30 @@ function updateStateWithChangedRange(state, change) {
706
865
  // retain all indexes that are within the new range
707
866
  const minIndex = indexFactory(inputStart);
708
867
  const maxIndex = indexFactory(inputEnd) + 1;
709
- const currentIndexes = Array.from(state.toggledIndexes);
868
+ const currentIndexes = [...state.toggledIndexes];
710
869
  const isInCurrentRange = isIndexNumberInIndexRangeFunction({ minIndex, maxIndex });
711
870
  const excludedIndexesInNewRange = currentIndexes.filter(isInCurrentRange);
712
871
  const toggledIndexes = new Set(excludedIndexesInNewRange);
713
872
  const nextState = { ...state, toggledIndexes, inputStart, inputEnd };
714
873
  return finalizeNewCalendarScheduleSelectionState(nextState);
715
874
  }
875
+ /**
876
+ * Finalizes a partially-built state by recomputing the isEnabledDay function and the current selection value.
877
+ *
878
+ * @param nextState - The partially-built selection state to finalize
879
+ * @returns The finalized selection state
880
+ */
716
881
  function finalizeNewCalendarScheduleSelectionState(nextState) {
717
882
  nextState.isEnabledDay = isEnabledDayInCalendarScheduleSelectionState(nextState);
718
883
  nextState.currentSelectionValue = computeScheduleSelectionValue(nextState);
719
884
  return nextState;
720
885
  }
886
+ /**
887
+ * Builds a decision function that determines whether a given day index is enabled (selected) in the current state.
888
+ *
889
+ * @param state - The selection state to derive the enabled-day function from
890
+ * @returns A function that returns true if the given day is enabled/selected
891
+ */
721
892
  function isEnabledDayInCalendarScheduleSelectionState(state) {
722
893
  const { allowedDaysOfWeek, indexFactory, inputStart, inputEnd, indexDayOfWeek, systemTimezone } = state;
723
894
  let isInStartAndEndRange;
@@ -733,10 +904,16 @@ function isEnabledDayInCalendarScheduleSelectionState(state) {
733
904
  const isInSelectedRange = isInStartAndEndRange(index);
734
905
  const isSelected = state.toggledIndexes.has(index);
735
906
  const isAllowedDayOfWeek = allowedDaysOfWeek.has(dayOfWeek);
736
- const result = isAllowedDayOfWeek && ((isInSelectedRange && !isSelected) || (isSelected && !isInSelectedRange));
737
- return result;
907
+ return isAllowedDayOfWeek && ((isInSelectedRange && !isSelected) || (isSelected && !isInSelectedRange));
738
908
  };
739
909
  }
910
+ /**
911
+ * Computes the output DateCellScheduleDateRange value from the current selection state,
912
+ * applying timezone offsets and filter-relative computations as needed.
913
+ *
914
+ * @param state - The current selection state to compute from
915
+ * @returns The computed selection value, or null if nothing is selected
916
+ */
740
917
  function computeScheduleSelectionValue(state) {
741
918
  const { indexFactory: systemIndexFactory, allowedDaysOfWeek, effectiveScheduleDays, indexDayOfWeek, computeSelectionResultRelativeToFilter, filter, systemTimezone } = state;
742
919
  let timezone = systemTimezone;
@@ -767,8 +944,8 @@ function computeScheduleSelectionValue(state) {
767
944
  }
768
945
  const excluded = computeSelectionResultRelativeToFilter
769
946
  ? allExcluded.filter((x) => {
770
- const isExcludedIndex = allowedDaysOfWeek.has(indexDayOfWeek(x)); // ???
771
- return isExcludedIndex;
947
+ // ???
948
+ return allowedDaysOfWeek.has(indexDayOfWeek(x));
772
949
  })
773
950
  : allExcluded;
774
951
  const offsetExcluded = excluded.map((x) => x - indexOffset); // set to the proper offset
@@ -792,6 +969,13 @@ function computeScheduleSelectionValue(state) {
792
969
  minMaxRange: { start, end }
793
970
  };
794
971
  }
972
+ /**
973
+ * Computes the selected date range with its corresponding cell range and all excluded day indexes.
974
+ * Returns null if no days are selected.
975
+ *
976
+ * @param state - The current selection state
977
+ * @returns The range and exclusion data, or null if nothing is selected
978
+ */
795
979
  function computeScheduleSelectionRangeAndExclusion(state) {
796
980
  const { start: currentStart, isEnabledDay, isEnabledFilterDay, systemTimezone } = state;
797
981
  const dateFactory = dateCellTimingStartDateFactory({ startsAt: currentStart, timezone: systemTimezone });
@@ -802,8 +986,7 @@ function computeScheduleSelectionRangeAndExclusion(state) {
802
986
  const start = dateFactory(dateCellRange.i);
803
987
  const end = dateFactory(dateCellRange.to);
804
988
  const excluded = range(dateCellRange.i, dateCellRange.to + 1).filter((x) => {
805
- const isExcludedIndex = !isEnabledDay(x) || !isEnabledFilterDay(x);
806
- return isExcludedIndex;
989
+ return !isEnabledDay(x) || !isEnabledFilterDay(x);
807
990
  });
808
991
  const result = {
809
992
  dateCellRange,
@@ -813,15 +996,27 @@ function computeScheduleSelectionRangeAndExclusion(state) {
813
996
  };
814
997
  return result;
815
998
  }
999
+ /**
1000
+ * Computes the selected date range (start and end dates) from the current selection state.
1001
+ *
1002
+ * @param state - The current selection state
1003
+ * @returns The selected date range, or undefined if nothing is selected
1004
+ */
816
1005
  function computeCalendarScheduleSelectionRange(state) {
817
1006
  const dateFactory = dateCellTimingDateFactory({ startsAt: state.start, timezone: state.systemTimezone });
818
1007
  const dateCellRange = computeCalendarScheduleSelectionDateCellRange(state);
819
1008
  const dateRange = dateCellRange != null ? { start: dateFactory(dateCellRange.i), end: dateFactory(dateCellRange.to) } : undefined;
820
1009
  return dateRange;
821
1010
  }
1011
+ /**
1012
+ * Computes the date cell index range (i, to) that spans all selected and toggled days in the current state.
1013
+ *
1014
+ * @param state - The current selection state
1015
+ * @returns The cell range spanning all selected days, or undefined if nothing is selected
1016
+ */
822
1017
  function computeCalendarScheduleSelectionDateCellRange(state) {
823
1018
  const { allowedDaysOfWeek, indexFactory, inputStart, inputEnd, indexDayOfWeek, isEnabledDay, isEnabledFilterDay } = state;
824
- const enabledExclusionIndexes = Array.from(state.toggledIndexes).filter((i) => allowedDaysOfWeek.has(indexDayOfWeek(i)));
1019
+ const enabledExclusionIndexes = [...state.toggledIndexes].filter((i) => allowedDaysOfWeek.has(indexDayOfWeek(i)));
825
1020
  const minAndMaxSelectedValues = minAndMaxNumber(enabledExclusionIndexes);
826
1021
  let startRange;
827
1022
  let endRange;
@@ -898,7 +1093,7 @@ function provideCalendarScheduleSelectionStoreIfParentIsUnavailable() {
898
1093
  return {
899
1094
  provide: DbxCalendarScheduleSelectionStore,
900
1095
  useFactory: (parentInjector, dbxCalendarScheduleSelectionStoreInjectionBlock, dbxCalendarScheduleSelectionStore) => {
901
- if (!dbxCalendarScheduleSelectionStore || (dbxCalendarScheduleSelectionStore && dbxCalendarScheduleSelectionStoreInjectionBlock != null && dbxCalendarScheduleSelectionStoreInjectionBlock.dbxCalendarScheduleSelectionStore === dbxCalendarScheduleSelectionStore)) {
1096
+ if (!dbxCalendarScheduleSelectionStore || (dbxCalendarScheduleSelectionStore && dbxCalendarScheduleSelectionStoreInjectionBlock?.dbxCalendarScheduleSelectionStore === dbxCalendarScheduleSelectionStore)) {
902
1097
  // create a new dbxCalendarScheduleSelectionStore to use
903
1098
  const injector = Injector.create({ providers: [{ provide: DbxCalendarScheduleSelectionStore }], parent: parentInjector });
904
1099
  dbxCalendarScheduleSelectionStore = injector.get(DbxCalendarScheduleSelectionStore);
@@ -909,10 +1104,21 @@ function provideCalendarScheduleSelectionStoreIfParentIsUnavailable() {
909
1104
  };
910
1105
  }
911
1106
 
1107
+ /**
1108
+ * Creates form fields for selecting which days of the week are enabled in a schedule selection calendar,
1109
+ * wrapped in a responsive flex layout.
1110
+ *
1111
+ * @returns An array of Formly field configs with toggle fields for each day of the week
1112
+ */
912
1113
  function dbxScheduleSelectionCalendarDateDaysFormFields() {
913
1114
  const fields = dbxScheduleSelectionCalendarDateDaysFormDayFields();
914
1115
  return [flexLayoutWrapper(fields, { relative: true, size: 3 })];
915
1116
  }
1117
+ /**
1118
+ * Creates an array of toggle field configs, one for each day of the week, keyed by lowercase day name.
1119
+ *
1120
+ * @returns An array of toggle Formly field configs for each day of the week
1121
+ */
916
1122
  function dbxScheduleSelectionCalendarDateDaysFormDayFields() {
917
1123
  return getDaysOfWeekNames(false).map((dayOfWeekName) => {
918
1124
  return toggleField({
@@ -946,8 +1152,7 @@ class DbxScheduleSelectionCalendarDateDaysComponent {
946
1152
  isFormModified = (value) => {
947
1153
  const newSetValue = new Set(dateCellScheduleDayCodesFromEnabledDays(value));
948
1154
  return this.dbxCalendarScheduleSelectionStore.scheduleDays$.pipe(map((currentSet) => {
949
- const result = !dateCellScheduleDayCodesAreSetsEquivalent(newSetValue, currentSet);
950
- return result;
1155
+ return !dateCellScheduleDayCodesAreSetsEquivalent(newSetValue, currentSet);
951
1156
  }));
952
1157
  };
953
1158
  updateScheduleDays = (value) => {
@@ -1005,7 +1210,7 @@ class DbxScheduleSelectionCalendarDateRangeComponent {
1005
1210
  end: new FormControl(null)
1006
1211
  });
1007
1212
  errorStateMatcher = {
1008
- isErrorState: (control, form) => {
1213
+ isErrorState: (control, _form) => {
1009
1214
  if (control) {
1010
1215
  return (control.invalid && (control.dirty || control.touched)) || (control.touched && this.range.invalid);
1011
1216
  }
@@ -1050,8 +1255,7 @@ class DbxScheduleSelectionCalendarDateRangeComponent {
1050
1255
  }), shareReplay(1));
1051
1256
  datePickerFilter$ = combineLatest([this.dbxCalendarScheduleSelectionStore.isEnabledFilterDayFunction$, this.dbxCalendarScheduleSelectionStore.isInAllowedDaysOfWeekFunction$]).pipe(map(([isEnabled, isAllowedDayOfWeek]) => {
1052
1257
  const fn = (date) => {
1053
- const result = date ? isAllowedDayOfWeek(date) && isEnabled(date) : true;
1054
- return result;
1258
+ return date ? isAllowedDayOfWeek(date) && isEnabled(date) : true;
1055
1259
  };
1056
1260
  return fn;
1057
1261
  }), shareReplay(1));
@@ -1066,7 +1270,7 @@ class DbxScheduleSelectionCalendarDateRangeComponent {
1066
1270
  ? [
1067
1271
  (control) => {
1068
1272
  const range = control.value;
1069
- if (!range || !range.start || !range.end) {
1273
+ if (!range?.start || !range.end) {
1070
1274
  return { required: true };
1071
1275
  }
1072
1276
  return null;
@@ -1329,7 +1533,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1329
1533
  }]
1330
1534
  }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1331
1535
 
1536
+ /**
1537
+ * Creates a factory that produces a beforeMonthViewRender handler for the schedule selection calendar.
1538
+ * The handler applies CSS classes and metadata to each day cell based on the current selection state.
1539
+ *
1540
+ * @param inputModifyFn - Optional function to further customize each day cell after default processing
1541
+ * @returns A factory function that accepts a state observable and produces a render handler
1542
+ */
1332
1543
  function dbxScheduleSelectionCalendarBeforeMonthViewRenderFactory(inputModifyFn) {
1544
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1333
1545
  const modifyFn = inputModifyFn || (() => { });
1334
1546
  return (state$) => {
1335
1547
  return (renderEvent) => {
@@ -1459,11 +1671,11 @@ class DbxScheduleSelectionCalendarComponent {
1459
1671
  this.beforeMonthViewRenderSignal()?.(renderEvent);
1460
1672
  }
1461
1673
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxScheduleSelectionCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1462
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: DbxScheduleSelectionCalendarComponent, isStandalone: true, selector: "dbx-schedule-selection-calendar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickEvent: "clickEvent" }, providers: [DbxCalendarStore], ngImport: i0, template: "<dbx-calendar-base class=\"dbx-schedule-selection-calendar\" [ngClass]=\"readonlySignal() ? 'dbx-schedule-selection-calendar-readonly' : ''\">\n <ng-container controls>\n @if (showClearSelectionButtonSignal()) {\n <dbx-schedule-selection-calendar-selection-toggle-button [disabled]=\"readonlySignal()\"></dbx-schedule-selection-calendar-selection-toggle-button>\n <dbx-button-spacer></dbx-button-spacer>\n }\n <dbx-injection [config]=\"datePopoverButtonInjectionConfigSignal()\"></dbx-injection>\n </ng-container>\n <div class=\"dbx-calendar-content dbx-calendar-content-month\">\n <mwl-calendar-month-view [refresh]=\"refresh$\" [viewDate]=\"viewDateSignal()!\" [events]=\"eventsSignal()\" (dayClicked)=\"dayClicked($event.day)\" (eventClicked)=\"eventClicked('Clicked', $event.event)\" (beforeViewRender)=\"beforeMonthViewRender($event)\" [cellTemplate]=\"monthDayCellTemplate\"></mwl-calendar-month-view>\n </div>\n</dbx-calendar-base>\n\n<!-- Cell -->\n<ng-template #monthDayCellTemplate let-day=\"day\" let-locale=\"locale\">\n <div class=\"cal-cell-top\">\n @if (day.badgeTotal > 0) {\n <span class=\"cal-day-badge\">{{ day.badgeTotal }}</span>\n }\n <span class=\"cal-day-number\">{{ day.date | calendarDate: 'monthViewDayNumber' : locale }}</span>\n </div>\n <dbx-schedule-selection-calendar-cell [day]=\"day\"></dbx-schedule-selection-calendar-cell>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CalendarModule }, { kind: "component", type: i1$5.CalendarMonthViewComponent, selector: "mwl-calendar-month-view", inputs: ["viewDate", "events", "excludeDays", "activeDayIsOpen", "activeDay", "refresh", "locale", "tooltipPlacement", "tooltipTemplate", "tooltipAppendToBody", "tooltipDelay", "weekStartsOn", "headerTemplate", "cellTemplate", "openDayEventsTemplate", "eventTitleTemplate", "eventActionsTemplate", "weekendDays"], outputs: ["beforeViewRender", "dayClicked", "eventClicked", "columnHeaderClicked", "eventTimesChanged"] }, { kind: "component", type: DbxCalendarBaseComponent, selector: "dbx-calendar-base" }, { kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "directive", type: DbxButtonSpacerDirective, selector: "dbx-button-spacer,[dbxButtonSpacer]" }, { kind: "component", type: DbxScheduleSelectionCalendarCellComponent, selector: "dbx-schedule-selection-calendar-cell", inputs: ["day"] }, { kind: "component", type: DbxScheduleSelectionCalendarSelectionToggleButtonComponent, selector: "dbx-schedule-selection-calendar-selection-toggle-button", inputs: ["disabled"] }, { kind: "pipe", type: i1$5.CalendarDatePipe, name: "calendarDate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1674
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: DbxScheduleSelectionCalendarComponent, isStandalone: true, selector: "dbx-schedule-selection-calendar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickEvent: "clickEvent" }, providers: [DbxCalendarStore], ngImport: i0, template: "<dbx-calendar-base class=\"dbx-schedule-selection-calendar\" [ngClass]=\"readonlySignal() ? 'dbx-schedule-selection-calendar-readonly' : ''\">\n <ng-container controls>\n @if (showClearSelectionButtonSignal()) {\n <dbx-schedule-selection-calendar-selection-toggle-button [disabled]=\"readonlySignal()\"></dbx-schedule-selection-calendar-selection-toggle-button>\n <dbx-button-spacer></dbx-button-spacer>\n }\n <dbx-injection [config]=\"datePopoverButtonInjectionConfigSignal()\"></dbx-injection>\n </ng-container>\n <div class=\"dbx-calendar-content dbx-calendar-content-month\">\n <mwl-calendar-month-view [refresh]=\"refresh$\" [viewDate]=\"viewDateSignal()!\" [events]=\"eventsSignal()\" (dayClicked)=\"dayClicked($event.day)\" (eventClicked)=\"eventClicked('Clicked', $event.event)\" (beforeViewRender)=\"beforeMonthViewRender($event)\" [cellTemplate]=\"monthDayCellTemplate\"></mwl-calendar-month-view>\n </div>\n</dbx-calendar-base>\n\n<!-- Cell -->\n<ng-template #monthDayCellTemplate let-day=\"day\" let-locale=\"locale\">\n <div class=\"cal-cell-top\">\n @if (day.badgeTotal > 0) {\n <span class=\"cal-day-badge\">{{ day.badgeTotal }}</span>\n }\n <span class=\"cal-day-number\">{{ day.date | calendarDate: 'monthViewDayNumber' : locale }}</span>\n </div>\n <dbx-schedule-selection-calendar-cell [day]=\"day\"></dbx-schedule-selection-calendar-cell>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CalendarMonthViewComponent, selector: "mwl-calendar-month-view", inputs: ["viewDate", "events", "excludeDays", "activeDayIsOpen", "activeDay", "refresh", "locale", "tooltipPlacement", "tooltipTemplate", "tooltipAppendToBody", "tooltipDelay", "weekStartsOn", "headerTemplate", "cellTemplate", "openDayEventsTemplate", "eventTitleTemplate", "eventActionsTemplate", "weekendDays"], outputs: ["beforeViewRender", "dayClicked", "eventClicked", "columnHeaderClicked", "eventTimesChanged"] }, { kind: "component", type: DbxCalendarBaseComponent, selector: "dbx-calendar-base" }, { kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "directive", type: DbxButtonSpacerDirective, selector: "dbx-button-spacer,[dbxButtonSpacer]" }, { kind: "component", type: DbxScheduleSelectionCalendarCellComponent, selector: "dbx-schedule-selection-calendar-cell", inputs: ["day"] }, { kind: "component", type: DbxScheduleSelectionCalendarSelectionToggleButtonComponent, selector: "dbx-schedule-selection-calendar-selection-toggle-button", inputs: ["disabled"] }, { kind: "pipe", type: CalendarDatePipe, name: "calendarDate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1463
1675
  }
1464
1676
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxScheduleSelectionCalendarComponent, decorators: [{
1465
1677
  type: Component,
1466
- args: [{ selector: 'dbx-schedule-selection-calendar', imports: [NgClass, CalendarModule, DbxCalendarBaseComponent, DbxInjectionComponent, DbxButtonSpacerDirective, DbxScheduleSelectionCalendarCellComponent, DbxScheduleSelectionCalendarSelectionToggleButtonComponent], providers: [DbxCalendarStore], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<dbx-calendar-base class=\"dbx-schedule-selection-calendar\" [ngClass]=\"readonlySignal() ? 'dbx-schedule-selection-calendar-readonly' : ''\">\n <ng-container controls>\n @if (showClearSelectionButtonSignal()) {\n <dbx-schedule-selection-calendar-selection-toggle-button [disabled]=\"readonlySignal()\"></dbx-schedule-selection-calendar-selection-toggle-button>\n <dbx-button-spacer></dbx-button-spacer>\n }\n <dbx-injection [config]=\"datePopoverButtonInjectionConfigSignal()\"></dbx-injection>\n </ng-container>\n <div class=\"dbx-calendar-content dbx-calendar-content-month\">\n <mwl-calendar-month-view [refresh]=\"refresh$\" [viewDate]=\"viewDateSignal()!\" [events]=\"eventsSignal()\" (dayClicked)=\"dayClicked($event.day)\" (eventClicked)=\"eventClicked('Clicked', $event.event)\" (beforeViewRender)=\"beforeMonthViewRender($event)\" [cellTemplate]=\"monthDayCellTemplate\"></mwl-calendar-month-view>\n </div>\n</dbx-calendar-base>\n\n<!-- Cell -->\n<ng-template #monthDayCellTemplate let-day=\"day\" let-locale=\"locale\">\n <div class=\"cal-cell-top\">\n @if (day.badgeTotal > 0) {\n <span class=\"cal-day-badge\">{{ day.badgeTotal }}</span>\n }\n <span class=\"cal-day-number\">{{ day.date | calendarDate: 'monthViewDayNumber' : locale }}</span>\n </div>\n <dbx-schedule-selection-calendar-cell [day]=\"day\"></dbx-schedule-selection-calendar-cell>\n</ng-template>\n" }]
1678
+ args: [{ selector: 'dbx-schedule-selection-calendar', imports: [NgClass, CalendarMonthViewComponent, CalendarDatePipe, DbxCalendarBaseComponent, DbxInjectionComponent, DbxButtonSpacerDirective, DbxScheduleSelectionCalendarCellComponent, DbxScheduleSelectionCalendarSelectionToggleButtonComponent], providers: [DbxCalendarStore], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<dbx-calendar-base class=\"dbx-schedule-selection-calendar\" [ngClass]=\"readonlySignal() ? 'dbx-schedule-selection-calendar-readonly' : ''\">\n <ng-container controls>\n @if (showClearSelectionButtonSignal()) {\n <dbx-schedule-selection-calendar-selection-toggle-button [disabled]=\"readonlySignal()\"></dbx-schedule-selection-calendar-selection-toggle-button>\n <dbx-button-spacer></dbx-button-spacer>\n }\n <dbx-injection [config]=\"datePopoverButtonInjectionConfigSignal()\"></dbx-injection>\n </ng-container>\n <div class=\"dbx-calendar-content dbx-calendar-content-month\">\n <mwl-calendar-month-view [refresh]=\"refresh$\" [viewDate]=\"viewDateSignal()!\" [events]=\"eventsSignal()\" (dayClicked)=\"dayClicked($event.day)\" (eventClicked)=\"eventClicked('Clicked', $event.event)\" (beforeViewRender)=\"beforeMonthViewRender($event)\" [cellTemplate]=\"monthDayCellTemplate\"></mwl-calendar-month-view>\n </div>\n</dbx-calendar-base>\n\n<!-- Cell -->\n<ng-template #monthDayCellTemplate let-day=\"day\" let-locale=\"locale\">\n <div class=\"cal-cell-top\">\n @if (day.badgeTotal > 0) {\n <span class=\"cal-day-badge\">{{ day.badgeTotal }}</span>\n }\n <span class=\"cal-day-number\">{{ day.date | calendarDate: 'monthViewDayNumber' : locale }}</span>\n </div>\n <dbx-schedule-selection-calendar-cell [day]=\"day\"></dbx-schedule-selection-calendar-cell>\n</ng-template>\n" }]
1467
1679
  }], propDecorators: { clickEvent: [{ type: i0.Output, args: ["clickEvent"] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }] } });
1468
1680
 
1469
1681
  /**
@@ -1690,7 +1902,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1690
1902
  const importsAndExports$1 = [DbxFormCalendarDateScheduleRangeFieldComponent];
1691
1903
  class DbxFormDateScheduleRangeFieldModule {
1692
1904
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxFormDateScheduleRangeFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1693
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: DbxFormDateScheduleRangeFieldModule, imports: [DbxFormCalendarDateScheduleRangeFieldComponent, i1$6.FormlyModule], exports: [DbxFormCalendarDateScheduleRangeFieldComponent] });
1905
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: DbxFormDateScheduleRangeFieldModule, imports: [DbxFormCalendarDateScheduleRangeFieldComponent, i1$5.FormlyModule], exports: [DbxFormCalendarDateScheduleRangeFieldComponent] });
1694
1906
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxFormDateScheduleRangeFieldModule, imports: [importsAndExports$1, FormlyModule.forChild({
1695
1907
  types: [{ name: 'date-schedule-range', component: DbxFormCalendarDateScheduleRangeFieldComponent }]
1696
1908
  })] });