@entur/datepicker 11.6.2 → 11.7.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.
@@ -6,10 +6,10 @@ import { useDateSegment, useDateField, useDatePicker, useTimeField } from "@reac
6
6
  import { useLocale, I18nProvider } from "@react-aria/i18n";
7
7
  import classNames from "classnames";
8
8
  import { BaseFormControl, useVariant, useInputGroupContext, isFilled, TextField } from "@entur/form";
9
- import { toTime, now, toZoned, toCalendarDateTime, today, toCalendarDate, GregorianCalendar, startOfWeek, startOfYear, CalendarDate, Time, getLocalTimeZone, ZonedDateTime, parseAbsolute, CalendarDateTime, isEqualDay, getWeeksInMonth, parseTime } from "@internationalized/date";
9
+ import { toTime, now, toZoned, toCalendarDateTime, today, toCalendarDate, GregorianCalendar, startOfWeek, startOfYear, CalendarDate, Time, getLocalTimeZone, ZonedDateTime, parseAbsolute, CalendarDateTime, isEqualDay, getWeeksInMonth, isSameDay, parseTime } from "@internationalized/date";
10
10
  import { CalendarDate as CalendarDate2, CalendarDateTime as CalendarDateTime2, Time as Time2, ZonedDateTime as ZonedDateTime2 } from "@internationalized/date";
11
- import { useCalendarCell, useCalendarGrid, useCalendar } from "@react-aria/calendar";
12
- import { useCalendarState } from "@react-stately/calendar";
11
+ import { useCalendarCell, useCalendarGrid, useCalendar, useRangeCalendar } from "@react-aria/calendar";
12
+ import { useCalendarState, useRangeCalendarState } from "@react-stately/calendar";
13
13
  import { LeftArrowIcon, RightArrowIcon, CalendarIcon, DateIcon, ClockIcon } from "@entur/icons";
14
14
  import { useButton } from "@react-aria/button";
15
15
  import { IconButton } from "@entur/button";
@@ -576,6 +576,270 @@ const CalendarBase = ({
576
576
  }
577
577
  );
578
578
  };
579
+ const RangeCalendarCell = ({
580
+ state,
581
+ date,
582
+ currentMonth,
583
+ showOutsideMonth = false,
584
+ weekNumberString,
585
+ classNameForDate,
586
+ ariaLabelForDate,
587
+ ...rest
588
+ }) => {
589
+ const cellRef = useRef(null);
590
+ const {
591
+ cellProps,
592
+ buttonProps,
593
+ isSelected,
594
+ isOutsideVisibleRange,
595
+ isDisabled,
596
+ isUnavailable,
597
+ formattedDate
598
+ } = useCalendarCell({ date }, state, cellRef);
599
+ const ariaLabel = `${buttonProps["aria-label"]}${weekNumberString} ${ariaLabelForDate?.(date) ?? ""}`;
600
+ const highlightedRange = state.highlightedRange;
601
+ const isSelectionStart = isSelected && highlightedRange ? isSameDay(date, highlightedRange.start) : isSelected;
602
+ const isSelectionEnd = isSelected && highlightedRange ? isSameDay(date, highlightedRange.end) : isSelected;
603
+ const isInRange = isSelected && !isSelectionStart && !isSelectionEnd;
604
+ const isOverflowDate = date.month !== currentMonth.month || date.year !== currentMonth.year;
605
+ const isBetweenVisibleMonths = isOverflowDate && !isOutsideVisibleRange;
606
+ const shouldHideDate = !showOutsideMonth && isOutsideVisibleRange;
607
+ const extendedButtonProps = {
608
+ ...buttonProps,
609
+ ...showOutsideMonth && isOutsideVisibleRange && {
610
+ onClick: () => state.selectDate(date),
611
+ onKeyUp: (e) => {
612
+ if (e.key === "Enter") state.selectDate(date);
613
+ }
614
+ },
615
+ ...isBetweenVisibleMonths && {
616
+ tabIndex: -1,
617
+ role: "presentation",
618
+ onClick: void 0,
619
+ onKeyDown: void 0,
620
+ onKeyUp: void 0,
621
+ onPointerDown: void 0,
622
+ onFocus: void 0
623
+ }
624
+ };
625
+ return /* @__PURE__ */ jsx("td", { ...cellProps, className: "eds-datepicker__calendar__grid__cell__td", children: /* @__PURE__ */ jsx(
626
+ "div",
627
+ {
628
+ ...extendedButtonProps,
629
+ "aria-label": isBetweenVisibleMonths ? void 0 : ariaLabel,
630
+ "aria-hidden": shouldHideDate || isBetweenVisibleMonths,
631
+ ref: cellRef,
632
+ hidden: shouldHideDate,
633
+ className: classNames("eds-datepicker__calendar__grid__cell", {
634
+ [classNameForDate?.(date) ?? ""]: !shouldHideDate,
635
+ "eds-datepicker__calendar__grid__cell--selected": isSelected && !isOverflowDate,
636
+ "eds-datepicker__calendar__grid__cell--selection-start": isSelectionStart && !isOverflowDate,
637
+ "eds-datepicker__calendar__grid__cell--selection-end": isSelectionEnd && !isOverflowDate,
638
+ "eds-datepicker__calendar__grid__cell--in-range": isInRange && !isOverflowDate,
639
+ "eds-datepicker__calendar__grid__cell--disabled": isDisabled || isUnavailable,
640
+ "eds-datepicker__calendar__grid__cell--outside-month": isOutsideVisibleRange && !showOutsideMonth,
641
+ "eds-datepicker__calendar__grid__cell--between-months": isBetweenVisibleMonths,
642
+ "eds-datepicker__calendar__grid__cell--outside-month--visible": isOutsideVisibleRange && showOutsideMonth,
643
+ "eds-datepicker__calendar__grid__cell--today": isEqualDay(
644
+ date,
645
+ now(state.timeZone ?? getLocalTimeZone())
646
+ )
647
+ }),
648
+ ...rest,
649
+ children: formattedDate
650
+ }
651
+ ) });
652
+ };
653
+ const RangeCalendarGrid = ({
654
+ state,
655
+ startDate,
656
+ navigationDescription,
657
+ showWeekNumbers,
658
+ weekNumberHeader,
659
+ showOutsideMonth = false,
660
+ classNameForDate,
661
+ ariaLabelForDate,
662
+ ...rest
663
+ }) => {
664
+ const calendarGridId = useRandomId("eds-calendar");
665
+ const { locale } = useLocale();
666
+ const gridStartDate = startDate ?? state.visibleRange.start;
667
+ const { gridProps, headerProps, weekDays } = useCalendarGrid(
668
+ { ...rest, startDate: gridStartDate },
669
+ state
670
+ );
671
+ const weeksInMonth = getWeeksInMonth(gridStartDate, locale);
672
+ const weeksArray = Array.from(Array(weeksInMonth).keys());
673
+ const weekDaysMapped = () => {
674
+ if (locale.toLowerCase().includes("no"))
675
+ return ["ma", "ti", "on", "to", "fr", "lø", "sø"];
676
+ if (locale.toLowerCase().includes("en")) {
677
+ if (weekDays[0] === "M")
678
+ return ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
679
+ if (weekDays[0] === "S")
680
+ return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
681
+ }
682
+ return weekDays.map((day) => day.toLowerCase());
683
+ };
684
+ const getNavigationDescription = () => {
685
+ if (navigationDescription) return navigationDescription;
686
+ if (locale.toLowerCase().includes("en"))
687
+ return "Use the arrow keys to navigate between dates";
688
+ return "Bruk piltastene til å navigere mellom datoer";
689
+ };
690
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
691
+ /* @__PURE__ */ jsxs(
692
+ "table",
693
+ {
694
+ ...gridProps,
695
+ cellSpacing: "0",
696
+ className: "eds-datepicker__calendar__grid",
697
+ children: [
698
+ /* @__PURE__ */ jsx("thead", { ...headerProps, children: /* @__PURE__ */ jsxs("tr", { children: [
699
+ showWeekNumbers && /* @__PURE__ */ jsx("th", { className: "eds-datepicker__calendar__grid__weeknumber-header", children: weekNumberHeader }),
700
+ weekDaysMapped().map((day) => /* @__PURE__ */ jsx("th", { children: day }, day))
701
+ ] }) }),
702
+ /* @__PURE__ */ jsx("tbody", { children: weeksArray.map((weekIndex) => {
703
+ const weekNumber = getWeekNumberForDate(
704
+ state.getDatesInWeek(weekIndex, gridStartDate)[0]
705
+ );
706
+ return /* @__PURE__ */ jsxs("tr", { children: [
707
+ showWeekNumbers && /* @__PURE__ */ jsx(
708
+ "th",
709
+ {
710
+ "aria-label": `${weekNumberHeader} ${weekNumber}`,
711
+ className: "eds-datepicker__calendar__grid__weeknumber",
712
+ children: weekNumber
713
+ }
714
+ ),
715
+ state.getDatesInWeek(weekIndex, gridStartDate).map(
716
+ (date, i) => date ? /* @__PURE__ */ jsx(
717
+ RangeCalendarCell,
718
+ {
719
+ state,
720
+ date,
721
+ currentMonth: gridStartDate,
722
+ "aria-describedby": calendarGridId + "description",
723
+ weekNumberString: showWeekNumbers ? `, ${weekNumberHeader} ${weekNumber},` : "",
724
+ classNameForDate,
725
+ ariaLabelForDate,
726
+ showOutsideMonth
727
+ },
728
+ `${date.month}.${date.day}`
729
+ ) : /* @__PURE__ */ jsx("td", {}, i)
730
+ )
731
+ ] }, weekIndex);
732
+ }) })
733
+ ]
734
+ }
735
+ ),
736
+ /* @__PURE__ */ jsx(VisuallyHidden, { id: calendarGridId + "description", children: getNavigationDescription() })
737
+ ] });
738
+ };
739
+ const RangeCalendar = ({
740
+ locale: localOverride,
741
+ ...rest
742
+ }) => {
743
+ const props = { isDisabled: rest.disabled, ...rest };
744
+ const { locale } = useLocale();
745
+ return /* @__PURE__ */ jsx(I18nProvider, { locale: localOverride ?? locale, children: /* @__PURE__ */ jsx(RangeCalendarBase, { ...props }) });
746
+ };
747
+ const RangeCalendarBase = ({
748
+ value,
749
+ onChange,
750
+ minDate,
751
+ maxDate,
752
+ showWeekNumbers = false,
753
+ weekNumberHeader = "uke",
754
+ showOutsideMonth = false,
755
+ visibleDuration,
756
+ style,
757
+ className,
758
+ navigationDescription,
759
+ classNameForDate,
760
+ ariaLabelForDate,
761
+ calendarRef,
762
+ ...rest
763
+ }) => {
764
+ const { locale } = useLocale();
765
+ const internalRef = useRef(null);
766
+ const ref = calendarRef ?? internalRef;
767
+ const _props = {
768
+ ...rest,
769
+ value,
770
+ onChange,
771
+ locale,
772
+ createCalendar,
773
+ minValue: minDate,
774
+ maxValue: getAdjustedMaxDate(maxDate),
775
+ visibleDuration
776
+ };
777
+ const state = useRangeCalendarState(_props);
778
+ const { calendarProps, prevButtonProps, nextButtonProps, title } = useRangeCalendar(_props, state, ref);
779
+ useEffect(
780
+ () => rest.onValidate?.(!state.isValueInvalid),
781
+ [state.isValueInvalid]
782
+ );
783
+ const monthCount = state.visibleRange.end.month - state.visibleRange.start.month + 1 + (state.visibleRange.end.year - state.visibleRange.start.year) * 12;
784
+ const getMonthTitle = (startDate) => new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(
785
+ new Date(startDate.year, startDate.month - 1)
786
+ );
787
+ return /* @__PURE__ */ jsx(
788
+ "div",
789
+ {
790
+ ...calendarProps,
791
+ ref,
792
+ className: classNames("eds-datepicker__calendar", className),
793
+ style,
794
+ children: /* @__PURE__ */ jsx("div", { className: "eds-datepicker__calendar__grids", children: Array.from({ length: monthCount }, (_, i) => {
795
+ const startDate = state.visibleRange.start.add({ months: i });
796
+ return /* @__PURE__ */ jsxs("div", { className: "eds-datepicker__calendar__month", children: [
797
+ /* @__PURE__ */ jsxs("div", { className: "eds-datepicker__calendar__header", children: [
798
+ i === 0 && /* @__PURE__ */ jsx(
799
+ CalendarButton,
800
+ {
801
+ ...prevButtonProps,
802
+ "aria-label": ariaLabelIfNorwegian(
803
+ "Forrige måned",
804
+ locale,
805
+ prevButtonProps
806
+ ),
807
+ children: /* @__PURE__ */ jsx(LeftArrowIcon, { size: 20 })
808
+ }
809
+ ),
810
+ /* @__PURE__ */ jsx("h2", { children: monthCount > 1 ? getMonthTitle(startDate) : title }),
811
+ i === monthCount - 1 && /* @__PURE__ */ jsx(
812
+ CalendarButton,
813
+ {
814
+ ...nextButtonProps,
815
+ "aria-label": ariaLabelIfNorwegian(
816
+ "Neste måned",
817
+ locale,
818
+ nextButtonProps
819
+ ),
820
+ children: /* @__PURE__ */ jsx(RightArrowIcon, { size: 20 })
821
+ }
822
+ )
823
+ ] }),
824
+ /* @__PURE__ */ jsx(
825
+ RangeCalendarGrid,
826
+ {
827
+ ...rest,
828
+ state,
829
+ startDate,
830
+ navigationDescription,
831
+ classNameForDate,
832
+ ariaLabelForDate,
833
+ showWeekNumbers,
834
+ weekNumberHeader,
835
+ showOutsideMonth
836
+ }
837
+ )
838
+ ] }, i);
839
+ }) })
840
+ }
841
+ );
842
+ };
579
843
  const DatePicker = ({
580
844
  selectedDate,
581
845
  locale,
@@ -1253,6 +1517,7 @@ export {
1253
1517
  DatePicker,
1254
1518
  NativeDatePicker,
1255
1519
  NativeTimePicker,
1520
+ RangeCalendar,
1256
1521
  SimpleTimePicker,
1257
1522
  Time2 as Time,
1258
1523
  TimePicker,