Skip to content

Commit

Permalink
DatePicker/MonthPicker: add support for translations provider (#3390)
Browse files Browse the repository at this point in the history
  • Loading branch information
HalvorHaugan authored Nov 27, 2024
1 parent 34538a1 commit 1f4ac7b
Show file tree
Hide file tree
Showing 20 changed files with 172 additions and 327 deletions.
5 changes: 5 additions & 0 deletions .changeset/moody-gorillas-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": patch
---

DatePicker/MonthPicker: Remove pointerEvents=none on CalendarIcon so that the title shows up as tooltip on hover
9 changes: 5 additions & 4 deletions @navikt/core/react/src/date/datepicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { DateRange, DayPicker, isMatch } from "react-day-picker";
import { omit } from "../../util";
import { useId } from "../../util/hooks";
import { useMergeRefs } from "../../util/hooks/useMergeRefs";
import { useDateLocale } from "../../util/i18n/i18n.context";
import { DateContext } from "../context";
import { DatePickerInput } from "../parts/DateInput";
import { DateWrapper } from "../parts/DateWrapper";
import { getLocaleFromString, labels } from "../utils";
import { getLocaleFromString } from "../utils";
import DatePickerStandalone from "./DatePickerStandalone";
import Caption from "./parts/Caption";
import DropdownCaption from "./parts/DropdownCaption";
Expand Down Expand Up @@ -66,7 +67,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
(
{
children,
locale = "nb",
locale,
dropdownCaption,
disabled = [],
disableWeekends = false,
Expand All @@ -85,6 +86,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
},
ref,
) => {
const langProviderLocale = useDateLocale();
const ariaId = useId(id);
const [open, setOpen] = useState(_open ?? false);

Expand Down Expand Up @@ -114,7 +116,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(

const DatePickerComponent = (
<DayPicker
locale={getLocaleFromString(locale)}
locale={locale ? getLocaleFromString(locale) : langProviderLocale}
mode={mode}
onSelect={handleSelect}
selected={selected ?? selectedDates}
Expand All @@ -134,7 +136,6 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
}}
weekStartsOn={1}
initialFocus={false}
labels={labels as any}
modifiers={{
weekend: (day) => disableWeekends && isWeekend(day),
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { isWeekend } from "date-fns";
import React, { forwardRef } from "react";
import { DateRange, DayPicker, isMatch } from "react-day-picker";
import { omit } from "../../util";
import { getLocaleFromString, labels } from "../utils";
import { useDateLocale } from "../../util/i18n/i18n.context";
import { getLocaleFromString } from "../utils";
import Caption from "./parts/Caption";
import DropdownCaption from "./parts/DropdownCaption";
import { HeadRow } from "./parts/HeadRow";
Expand Down Expand Up @@ -49,7 +50,7 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
(
{
className,
locale = "nb",
locale,
dropdownCaption,
disabled = [],
disableWeekends = false,
Expand All @@ -63,6 +64,7 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
},
ref,
) => {
const langProviderLocale = useDateLocale();
const [selectedDates, setSelectedDates] = React.useState<
Date | Date[] | DateRange | undefined
>(defaultSelected);
Expand All @@ -83,7 +85,7 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
className={cl("navds-date__standalone-wrapper", className)}
>
<DayPicker
locale={getLocaleFromString(locale)}
locale={locale ? getLocaleFromString(locale) : langProviderLocale}
mode={mode}
onSelect={handleSelect}
selected={selected ?? selectedDates}
Expand All @@ -103,7 +105,6 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
}}
weekStartsOn={1}
initialFocus={false}
labels={labels as any}
modifiers={{
weekend: (day) => disableWeekends && isWeekend(day),
}}
Expand Down
11 changes: 5 additions & 6 deletions @navikt/core/react/src/date/datepicker/parts/Caption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { CaptionProps, useDayPicker, useNavigation } from "react-day-picker";
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
import { Button } from "../../../button";
import { Label } from "../../../typography";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";
import WeekRow from "./WeekRow";

/**
Expand All @@ -11,13 +13,10 @@ import WeekRow from "./WeekRow";
export const DatePickerCaption = ({ displayMonth, id }: CaptionProps) => {
const { goToMonth, nextMonth, previousMonth } = useNavigation();
const {
labels: { labelPrevious, labelNext },
formatters: { formatCaption },
locale,
} = useDayPicker();

const previousLabel = labelPrevious(previousMonth, { locale });
const nextLabel = labelNext(nextMonth, { locale });
const translate = useI18n("DatePicker", getTranslations(locale.code));

return (
<>
Expand All @@ -26,7 +25,7 @@ export const DatePickerCaption = ({ displayMonth, id }: CaptionProps) => {
variant="tertiary"
disabled={!previousMonth}
onClick={() => previousMonth && goToMonth(previousMonth)}
icon={<ArrowLeftIcon title={previousLabel} />}
icon={<ArrowLeftIcon title={translate("goToPreviousMonth")} />}
className="navds-date__caption-button"
type="button"
/>
Expand All @@ -40,7 +39,7 @@ export const DatePickerCaption = ({ displayMonth, id }: CaptionProps) => {
{formatCaption(displayMonth, { locale })}
</Label>
<Button
icon={<ArrowRightIcon title={nextLabel} />}
icon={<ArrowRightIcon title={translate("goToNextMonth")} />}
onClick={() => nextMonth && goToMonth(nextMonth)}
disabled={!nextMonth}
variant="tertiary"
Expand Down
19 changes: 7 additions & 12 deletions @navikt/core/react/src/date/datepicker/parts/DropdownCaption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { CaptionProps, useDayPicker, useNavigation } from "react-day-picker";
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
import { Button } from "../../../button";
import { Select } from "../../../form/select";
import { getMonths, getYears } from "../../utils/get-dates";
import { labelMonthDropdown, labelYearDropdown } from "../../utils/labels";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getMonths, getTranslations, getYears } from "../../utils";
import WeekRow from "./WeekRow";

/**
Expand All @@ -17,9 +17,9 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
fromDate,
toDate,
formatters: { formatYearCaption, formatMonthCaption, formatCaption },
labels: { labelPrevious, labelNext },
locale,
} = useDayPicker();
const translate = useI18n("DatePicker", getTranslations(locale.code));

if (!fromDate || !toDate) {
console.warn("Using dropdownCaption required fromDate and toDate");
Expand All @@ -44,11 +44,6 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
).reverse();
const months = getMonths(fromDate, toDate, displayMonth);

const previousLabel = labelPrevious(previousMonth, { locale });
const nextLabel = labelNext(nextMonth, { locale });
const yearDropdownLabel = labelYearDropdown(locale);
const MonthDropdownLabel = labelMonthDropdown(locale);

return (
<>
<div className="navds-date__caption">
Expand All @@ -64,14 +59,14 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
variant="tertiary"
disabled={!previousMonth}
onClick={() => previousMonth && goToMonth(previousMonth)}
icon={<ArrowLeftIcon title={previousLabel} />}
icon={<ArrowLeftIcon title={translate("goToPreviousMonth")} />}
className="navds-date__caption-button"
type="button"
/>

<div className="navds-date__caption">
<Select
label={MonthDropdownLabel}
label={translate("month")}
hideLabel
className="navds-date__caption__month"
value={displayMonth.getMonth()}
Expand All @@ -84,7 +79,7 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
))}
</Select>
<Select
label={yearDropdownLabel}
label={translate("year")}
hideLabel
value={displayMonth.getFullYear()}
onChange={handleYearChange}
Expand All @@ -99,7 +94,7 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
</div>

<Button
icon={<ArrowRightIcon title={nextLabel} />}
icon={<ArrowRightIcon title={translate("goToNextMonth")} />}
onClick={() => nextMonth && goToMonth(nextMonth)}
disabled={!nextMonth}
variant="tertiary"
Expand Down
47 changes: 12 additions & 35 deletions @navikt/core/react/src/date/datepicker/parts/WeekNumber.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,52 @@
/* https://github.com/gpbl/react-day-picker/blob/7f78cd5/src/components/WeekNumber/WeekNumber.tsx#L21 */
import React from "react";
import { Button, useDayPicker } from "react-day-picker";
import { labelWeekNumber, labelWeekNumberButton } from "../../utils/labels";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";

export interface WeekNumberProps {
/** The number of the week. */
number: number;
/** The dates in the week. */
dates: Date[];
headerVersion?: boolean;
}

/**
* https://github.com/gpbl/react-day-picker/tree/main/src/components/WeekNumber
*/
function WeekNumber(props: WeekNumberProps): JSX.Element {
const { number: weekNumber, dates } = props;
function WeekNumber({
number: weekNumber,
dates,
}: WeekNumberProps): JSX.Element {
const {
onWeekNumberClick,
styles,
classNames,
locale: { code },
} = useDayPicker();

const weekLabel = labelWeekNumber({
week: Number(weekNumber),
localeCode: code,
});
const translate = useI18n("DatePicker", getTranslations(code));

if (!onWeekNumberClick) {
return (
<span
className={classNames.weeknumber}
style={styles.weeknumber}
aria-label={weekLabel}
aria-label={translate("weekNumber", { week: weekNumber })}
>
{weekNumber}
</span>
);
}

const label = labelWeekNumberButton({
week: Number(weekNumber),
localeCode: code,
});

const handleClick: React.MouseEventHandler = function (e) {
onWeekNumberClick(weekNumber, dates, e);
};

if (props?.headerVersion) {
return (
<Button
name="week-number"
aria-label={label}
className={classNames.weeknumber}
style={styles.weeknumber}
onClick={handleClick}
>
{weekNumber}
</Button>
);
}

return (
<Button
name="week-number"
aria-label={label}
aria-label={translate("selectWeekNumber", { week: weekNumber })}
className={classNames.weeknumber}
style={styles.weeknumber}
onClick={handleClick}
onClick={(event) => {
onWeekNumberClick(weekNumber, dates, event);
}}
>
{weekNumber}
</Button>
Expand Down
13 changes: 5 additions & 8 deletions @navikt/core/react/src/date/datepicker/parts/WeekRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { useDayPicker } from "react-day-picker";
import { Show } from "../../../layout/responsive";
import { Detail } from "../../../typography";
import { useId } from "../../../util/hooks";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";
import { getMonthWeeks } from "../../utils/get-month-weeks";
import { labelWeek } from "../../utils/labels";
import WeekNumber from "./WeekNumber";

const WeekRow = ({ displayMonth }: { displayMonth: Date }) => {
const { locale, fixedWeeks, onWeekNumberClick } = useDayPicker();

const translate = useI18n("DatePicker", getTranslations(locale.code));
const labelId = useId();

if (!onWeekNumberClick) {
Expand All @@ -32,7 +33,7 @@ const WeekRow = ({ displayMonth }: { displayMonth: Date }) => {
className="rdp-cell navds-date__week-cell"
>
<span className="navds-date__week-wrapper" id={labelId}>
{labelWeek(locale?.code)}
{`${translate("week")}:`}
</span>
</Detail>

Expand All @@ -42,11 +43,7 @@ const WeekRow = ({ displayMonth }: { displayMonth: Date }) => {
className="rdp-cell navds-date__week-cell"
>
<span className="navds-date__week-wrapper">
<WeekNumber
number={week.weekNumber}
dates={week.dates}
headerVersion
/>
<WeekNumber number={week.weekNumber} dates={week.dates} />
</span>
</td>
))}
Expand Down
6 changes: 4 additions & 2 deletions @navikt/core/react/src/date/hooks/useDatepicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { differenceInCalendarDays, isWeekend } from "date-fns";
import React, { useCallback, useState } from "react";
import { DayClickEventHandler, isMatch } from "react-day-picker";
import { useDateLocale } from "../../util/i18n/i18n.context";
import { DatePickerProps } from "../datepicker/DatePicker";
import { DateInputProps } from "../parts/DateInput";
import {
Expand Down Expand Up @@ -130,7 +131,7 @@ export const useDatepicker = (
opt: UseDatepickerOptions = {},
): UseDatepickerValue => {
const {
locale: _locale = "nb",
locale: _locale,
required,
defaultSelected: _defaultSelected,
today = new Date(),
Expand All @@ -146,7 +147,8 @@ export const useDatepicker = (
} = opt;

const [anchorRef, setAnchorRef] = useState<HTMLButtonElement | null>(null);
const locale = getLocaleFromString(_locale);
const localeFromProvider = useDateLocale();
const locale = _locale ? getLocaleFromString(_locale) : localeFromProvider;

const [defaultSelected, setDefaultSelected] = useState(_defaultSelected);

Expand Down
6 changes: 4 additions & 2 deletions @navikt/core/react/src/date/hooks/useMonthPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useCallback, useMemo, useState } from "react";
import { useDateLocale } from "../../util/i18n/i18n.context";
import { MonthPickerProps } from "../monthpicker/types";
import { DateInputProps } from "../parts/DateInput";
import {
Expand Down Expand Up @@ -126,7 +127,7 @@ export const useMonthpicker = (
opt: UseMonthPickerOptions = {},
): UseMonthPickerValue => {
const {
locale: _locale = "nb",
locale: _locale,
defaultSelected: _defaultSelected,
fromDate,
toDate,
Expand All @@ -143,7 +144,8 @@ export const useMonthpicker = (
const [defaultSelected, setDefaultSelected] = useState(_defaultSelected);

const today = useMemo(() => new Date(), []);
const locale = getLocaleFromString(_locale);
const localeFromProvider = useDateLocale();
const locale = _locale ? getLocaleFromString(_locale) : localeFromProvider;

// Initialize states
const [year, setYear] = useState(defaultSelected ?? defaultYear ?? today);
Expand Down
Loading

0 comments on commit 1f4ac7b

Please sign in to comment.