From b2e6b0171e45520a7c94021f481ab6935e49f916 Mon Sep 17 00:00:00 2001 From: Ken Date: Sun, 24 Sep 2023 19:11:50 +0200 Subject: [PATCH 01/27] :art: Standalone-demo --- .../react/src/date/datepicker/DatePicker.tsx | 5 ++++- .../date/datepicker/datepicker.stories.tsx | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/@navikt/core/react/src/date/datepicker/DatePicker.tsx b/@navikt/core/react/src/date/datepicker/DatePicker.tsx index e10da734a2..2510d59db3 100644 --- a/@navikt/core/react/src/date/datepicker/DatePicker.tsx +++ b/@navikt/core/react/src/date/datepicker/DatePicker.tsx @@ -49,7 +49,10 @@ export type ConditionalModeProps = //github.com/gpbl/react-day-picker/blob/50b6dba/packages/react-day-picker/src/types/DayPickerBase.ts#L139 export interface DatePickerDefaultProps extends Omit, "onSelect">, - Pick { + Pick< + DayPickerBase, + "month" | "onMonthChange" | "today" | "onDayClick" | "onWeekNumberClick" + > { /** * Element datepicker anchors to. Use for built-in toggle, or make your own with the open/onClose props */ diff --git a/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx b/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx index 073662e98b..55ebc1289f 100644 --- a/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx +++ b/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx @@ -2,7 +2,7 @@ import { Meta, StoryObj } from "@storybook/react"; import React, { useId, useState } from "react"; import { useDatepicker, useRangeDatepicker } from ".."; -import { Button } from "../.."; +import { Button, HGrid } from "../.."; import DatePicker, { DatePickerProps } from "./DatePicker"; const disabledDays = [ @@ -367,3 +367,23 @@ export const Readonly = () => { ); }; + +export const StandaloneOptions = () => { + return ( + + + + + + + ); +}; From e8ff1c025f24ad3b12c14794f4fb3330f5c5a8e4 Mon Sep 17 00:00:00 2001 From: Ken Date: Sun, 24 Sep 2023 19:16:21 +0200 Subject: [PATCH 02/27] :lipstick: Caption order --- @navikt/core/css/date.css | 14 ----- .../src/date/datepicker/caption/Caption.tsx | 39 ++++++------- .../datepicker/caption/DropdownCaption.tsx | 56 +++++++++---------- 3 files changed, 45 insertions(+), 64 deletions(-) diff --git a/@navikt/core/css/date.css b/@navikt/core/css/date.css index 4436d7ad4e..2a75fb0822 100644 --- a/@navikt/core/css/date.css +++ b/@navikt/core/css/date.css @@ -33,20 +33,6 @@ border-radius: var(--a-border-radius-small); } -.navds-date__caption-dropdown { - display: flex; - justify-content: space-between; - gap: var(--a-spacing-2); - align-items: center; -} - -.navds-date__caption__month-wrapper { - display: flex; - justify-content: center; - gap: var(--a-spacing-2); - align-items: center; -} - .navds-date__caption__month .navds-select__container select { text-transform: capitalize; } diff --git a/@navikt/core/react/src/date/datepicker/caption/Caption.tsx b/@navikt/core/react/src/date/datepicker/caption/Caption.tsx index 152d3eb5b1..42fb73be08 100644 --- a/@navikt/core/react/src/date/datepicker/caption/Caption.tsx +++ b/@navikt/core/react/src/date/datepicker/caption/Caption.tsx @@ -16,6 +16,15 @@ export const DatePickerCaption = ({ displayMonth, id }: CaptionProps) => { return (
+
+ + ); +} diff --git a/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx b/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx index 8ac6114ad6..822e72700b 100644 --- a/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx +++ b/@navikt/core/react/src/date/datepicker/datepicker.stories.tsx @@ -371,24 +371,34 @@ export const Readonly = () => { export const StandaloneOptions = () => { return ( - + + - ); diff --git a/@navikt/core/react/src/date/utils/labels.ts b/@navikt/core/react/src/date/utils/labels.ts index 6323cac0b5..99c9af082b 100644 --- a/@navikt/core/react/src/date/utils/labels.ts +++ b/@navikt/core/react/src/date/utils/labels.ts @@ -82,3 +82,41 @@ export const labels: Partial = { labelNext, labelPrevious, }; + +export const labelWeekNumber = ({ + localeCode, + week, +}: { + localeCode?: string; + week: number; +}): string => { + switch (localeCode) { + case "nb": + return `Uke ${week}`; + case "nn": + return `Veke ${week}`; + case "en-GB": + return `Week ${week}`; + default: + return `Uke ${week}`; + } +}; + +export const labelWeekNumberButton = ({ + localeCode, + week, +}: { + localeCode?: string; + week: number; +}): string => { + switch (localeCode) { + case "nb": + return `Velg uke ${week}`; + case "nn": + return `Velj veke ${week}`; + case "en-GB": + return `Pick week ${week}`; + default: + return `Velg uke ${week}`; + } +}; From 79e29d3d4962174adcd70492821ec99d870a1f3f Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 10:31:00 +0200 Subject: [PATCH 06/27] :sparkles: add AsChild to show/hide --- @navikt/core/css/primitives/responsive.css | 36 +++++++++---------- .../src/layout/responsive/Responsive.tsx | 20 +++++++++-- .../src/layout/responsive/hide.stories.tsx | 35 ++++++++++++++++++ .../src/layout/responsive/show.stories.tsx | 35 ++++++++++++++++++ 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/@navikt/core/css/primitives/responsive.css b/@navikt/core/css/primitives/responsive.css index 9f4adbfaa6..e5501ddcc1 100644 --- a/@navikt/core/css/primitives/responsive.css +++ b/@navikt/core/css/primitives/responsive.css @@ -1,51 +1,47 @@ -.navds-responsive { - display: none; -} - @media (min-width: 480px) { - .navds-responsive__above--sm { - display: revert; + .navds-responsive__below--sm { + display: none !important; } } @media (max-width: 479px) { - .navds-responsive__below--sm { - display: revert; + .navds-responsive__above--sm { + display: none !important; } } @media (min-width: 768px) { - .navds-responsive__above--md { - display: revert; + .navds-responsive__below--md { + display: none !important; } } @media (max-width: 767px) { - .navds-responsive__below--md { - display: revert; + .navds-responsive__above--md { + display: none !important; } } @media (min-width: 1024px) { - .navds-responsive__above--lg { - display: revert; + .navds-responsive__below--lg { + display: none !important; } } @media (max-width: 1023px) { - .navds-responsive__below--lg { - display: revert; + .navds-responsive__above--lg { + display: none !important; } } @media (min-width: 1280px) { - .navds-responsive__above--xl { - display: revert; + .navds-responsive__below--xl { + display: none !important; } } @media (max-width: 1279px) { - .navds-responsive__below--xl { - display: revert; + .navds-responsive__above--xl { + display: none !important; } } diff --git a/@navikt/core/react/src/layout/responsive/Responsive.tsx b/@navikt/core/react/src/layout/responsive/Responsive.tsx index d0bc212f8b..777204112e 100644 --- a/@navikt/core/react/src/layout/responsive/Responsive.tsx +++ b/@navikt/core/react/src/layout/responsive/Responsive.tsx @@ -1,6 +1,7 @@ import cl from "clsx"; import React, { forwardRef, HTMLAttributes } from "react"; import { BreakpointsAlias } from "../utilities/css"; +import { Slot } from "../../util/Slot"; export interface ResponsiveProps extends HTMLAttributes { children: React.ReactNode; @@ -19,6 +20,11 @@ export interface ResponsiveProps extends HTMLAttributes { * @default "div" */ as?: "div" | "span"; + + /** + * + */ + asChild?: boolean; } const Responsive = forwardRef< @@ -26,14 +32,24 @@ const Responsive = forwardRef< ResponsiveProps & { variant: "show" | "hide" } >( ( - { as: Component = "div", className, above, below, variant, ...rest }, + { + as: Component = "div", + className, + above, + below, + variant, + asChild, + ...rest + }, ref ) => { const aboveProp = variant === "show" ? above : below; const belowProp = variant === "show" ? below : above; + const Comp = asChild ? Slot : Component; + return ( - ), }; + +export const AsChild = { + render: () => ( + + + + Hidden above xl + + + Hidden above lg + + + Hidden above md + + + Hidden above sm + + + + + Hidden below xl + + + Hidden below lg + + + Hidden below md + + + Hidden below sm + + + + ), +}; diff --git a/@navikt/core/react/src/layout/responsive/show.stories.tsx b/@navikt/core/react/src/layout/responsive/show.stories.tsx index 0644faad62..1952891233 100644 --- a/@navikt/core/react/src/layout/responsive/show.stories.tsx +++ b/@navikt/core/react/src/layout/responsive/show.stories.tsx @@ -43,3 +43,38 @@ export const Default = { ), }; + +export const AsChild = { + render: () => ( + + + + Visible above xl + + + Visible above lg + + + Visible above md + + + Visible above sm + + + + + Visible below xl + + + Visible below lg + + + Visible below md + + + Visible below sm + + + + ), +}; From 6c8785ecf640f9ed751e427b1e2432639cb93fa2 Mon Sep 17 00:00:00 2001 From: Ken Date: Mon, 25 Sep 2023 16:52:05 +0200 Subject: [PATCH 07/27] :art: clickable week --- @navikt/core/css/date.css | 27 +++- .../date/datepicker/DatePickerStandalone.tsx | 8 +- .../react/src/date/datepicker/HeadRow.tsx | 56 ++++++++ .../core/react/src/date/datepicker/Row.tsx | 44 ++++++ .../react/src/date/datepicker/WeekNumber.tsx | 15 ++ .../src/date/datepicker/caption/Caption.tsx | 62 +++++---- .../datepicker/caption/DropdownCaption.tsx | 114 ++++++++-------- .../src/date/datepicker/caption/WeekRow.tsx | 128 ++++++++++++++++++ 8 files changed, 364 insertions(+), 90 deletions(-) create mode 100644 @navikt/core/react/src/date/datepicker/HeadRow.tsx create mode 100644 @navikt/core/react/src/date/datepicker/Row.tsx create mode 100644 @navikt/core/react/src/date/datepicker/caption/WeekRow.tsx diff --git a/@navikt/core/css/date.css b/@navikt/core/css/date.css index 70d8c7a9ee..2ab2f9a966 100644 --- a/@navikt/core/css/date.css +++ b/@navikt/core/css/date.css @@ -24,8 +24,9 @@ .navds-date .rdp-weeknumber { font-size: var(--a-font-size-small); - display: grid; - place-content: center; + display: flex; + align-items: center; + justify-content: center; width: 2rem; height: 2rem; border-radius: var(--a-border-radius-medium); @@ -36,7 +37,7 @@ .navds-date .rdp-weeknumber.rdp-button { width: 2rem; height: 2rem; - border: 1px solid var(--a-border-default); + box-shadow: 0 0 0 1px var(--a-border-default); color: var(--a-text-subtle); font-size: var(--a-font-size-small); } @@ -44,7 +45,7 @@ .navds-date .rdp-weeknumber.rdp-button:active { background-color: var(--a-surface-action-active); color: var(--a-text-on-action); - border-color: transparent; + box-shadow: none; } .navds-date__caption__month .navds-select__container select { @@ -295,6 +296,24 @@ height: 2rem; } +.navds-date__week { + display: flex; + align-items: center; + gap: 2px; +} + +.navds-date__week-button { + width: calc(3rem + 2px); + height: calc(3rem + 2px); + display: grid; + place-content: center; +} + +.navds-date__week-text { + width: 3.4rem; + text-align: center; +} + @media (min-width: 480px) { .navds-date { padding: var(--a-spacing-5) var(--a-spacing-4); diff --git a/@navikt/core/react/src/date/datepicker/DatePickerStandalone.tsx b/@navikt/core/react/src/date/datepicker/DatePickerStandalone.tsx index 9445407844..1ff361dbf5 100644 --- a/@navikt/core/react/src/date/datepicker/DatePickerStandalone.tsx +++ b/@navikt/core/react/src/date/datepicker/DatePickerStandalone.tsx @@ -5,14 +5,13 @@ import { DateRange, DayPicker, DayPickerBase, - isMatch, SelectMultipleEventHandler, SelectRangeEventHandler, SelectSingleEventHandler, + isMatch, } from "react-day-picker"; import { omit } from "../.."; import { getLocaleFromString, labels } from "../utils"; -import { Caption, DropdownCaption } from "./caption"; import { DatePickerDefaultProps, MultipleMode, @@ -21,6 +20,9 @@ import { } from "./DatePicker"; import { TableHead } from "./TableHead"; import { WeekNumber } from "./WeekNumber"; +import { Caption, DropdownCaption } from "./caption"; +import { Row } from "./Row"; +import { HeadRow } from "./HeadRow"; interface DatePickerStandaloneDefaultProps extends Omit< @@ -112,7 +114,9 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef< components={{ Caption: dropdownCaption ? DropdownCaption : Caption, Head: TableHead, + HeadRow, WeekNumber, + Row, }} className="navds-date" classNames={{ vhidden: "navds-sr-only" }} diff --git a/@navikt/core/react/src/date/datepicker/HeadRow.tsx b/@navikt/core/react/src/date/datepicker/HeadRow.tsx new file mode 100644 index 0000000000..ca3528c917 --- /dev/null +++ b/@navikt/core/react/src/date/datepicker/HeadRow.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import { addDays, Locale, startOfWeek } from "date-fns"; +import { useDayPicker } from "react-day-picker"; +import { Hide } from "../../layout/responsive"; + +/** + * Render the HeadRow component - i.e. the table head row with the weekday names. + */ +export function HeadRow(): JSX.Element { + const { + classNames, + styles, + showWeekNumber, + locale, + formatters: { formatWeekdayName }, + labels: { labelWeekday }, + } = useDayPicker(); + + const weekdays = getWeekdays(locale); + + return ( + + {showWeekNumber && ( + + + + )} + {weekdays.map((weekday, i) => ( + + {formatWeekdayName(weekday, { locale })} + + ))} + + ); +} + +/** + * Generate a series of 7 days, starting from the week, to use for formatting + * the weekday names (Monday, Tuesday, etc.). + */ +export function getWeekdays(locale?: Locale): Date[] { + const start = startOfWeek(new Date(), { locale, weekStartsOn: 1 }); + + const days: Date[] = []; + for (let i = 0; i < 7; i++) { + const day = addDays(start, i); + days.push(day); + } + return days; +} diff --git a/@navikt/core/react/src/date/datepicker/Row.tsx b/@navikt/core/react/src/date/datepicker/Row.tsx new file mode 100644 index 0000000000..462c09237a --- /dev/null +++ b/@navikt/core/react/src/date/datepicker/Row.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { getUnixTime } from "date-fns"; +import { useDayPicker, Day } from "react-day-picker"; +import { WeekNumber } from "./WeekNumber"; +import { Hide } from "../../layout/responsive"; + +/** + * The props for the {@link Row} component. + */ +export interface RowProps { + /** The month where the row is displayed. */ + displayMonth: Date; + /** The number of the week to render. */ + weekNumber: number; + /** The days contained in the week. */ + dates: Date[]; +} + +/** Render a row in the calendar, with the days and the week number. */ +export function Row(props: RowProps): JSX.Element { + const { styles, classNames, showWeekNumber } = useDayPicker(); + + return ( + + {showWeekNumber && ( + + + + + + )} + {props.dates.map((date) => ( + + + + ))} + + ); +} diff --git a/@navikt/core/react/src/date/datepicker/WeekNumber.tsx b/@navikt/core/react/src/date/datepicker/WeekNumber.tsx index a678cc183a..8afeb58faa 100644 --- a/@navikt/core/react/src/date/datepicker/WeekNumber.tsx +++ b/@navikt/core/react/src/date/datepicker/WeekNumber.tsx @@ -8,6 +8,7 @@ export interface WeekNumberProps { number: number; /** The dates in the week. */ dates: Date[]; + headerVersion?: boolean; } /** @@ -49,6 +50,20 @@ export function WeekNumber(props: WeekNumberProps): JSX.Element { onWeekNumberClick(weekNumber, dates, e); }; + if (props?.headerVersion) { + return ( + + ); + } + return (