diff --git a/src/components/duet-date-picker/date-localization.ts b/src/components/duet-date-picker/date-localization.ts index c5916f8..89a1d6a 100644 --- a/src/components/duet-date-picker/date-localization.ts +++ b/src/components/duet-date-picker/date-localization.ts @@ -15,6 +15,8 @@ export type DuetLocalizedText = { dayNames: DayNames monthNames: MonthsNames monthNamesShort: MonthsNames + weekNumber: string + weekNumberShort: string } const localization: DuetLocalizedText = { @@ -44,6 +46,8 @@ const localization: DuetLocalizedText = { "December", ], monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + weekNumber: "Week", + weekNumberShort: "#", } export default localization diff --git a/src/components/duet-date-picker/date-picker-month.tsx b/src/components/duet-date-picker/date-picker-month.tsx index 22eafa3..1c83a7f 100644 --- a/src/components/duet-date-picker/date-picker-month.tsx +++ b/src/components/duet-date-picker/date-picker-month.tsx @@ -2,7 +2,7 @@ import { h, FunctionalComponent } from "@stencil/core" import { DuetDateFormatter } from "./date-adapter" import { DuetLocalizedText } from "./date-localization" import { DatePickerDay, DatePickerDayProps } from "./date-picker-day" -import { getViewOfMonth, inRange, DaysOfWeek, isEqual } from "./date-utils" +import { getViewOfMonth, inRange, DaysOfWeek, isEqual, weekOfYear } from "./date-utils" function chunk(array: T[], chunkSize: number): T[][] { const result = [] @@ -35,6 +35,7 @@ type DatePickerMonthProps = { focusedDayRef: (element: HTMLButtonElement) => void onFocusIn?: (e: FocusEvent) => void onMouseDown?: (e: MouseEvent) => void + weekNumbers?: boolean } export const DatePickerMonth: FunctionalComponent = ({ @@ -51,6 +52,7 @@ export const DatePickerMonth: FunctionalComponent = ({ focusedDayRef, onMouseDown, onFocusIn, + weekNumbers, }) => { const today = new Date() const days = getViewOfMonth(focusedDate, firstDayOfWeek) @@ -66,6 +68,12 @@ export const DatePickerMonth: FunctionalComponent = ({ > + {weekNumbers && ( + + + {localization.weekNumber} + + )} {mapWithOffset(localization.dayNames, firstDayOfWeek, dayName => ( @@ -77,6 +85,7 @@ export const DatePickerMonth: FunctionalComponent = ({ {chunk(days, 7).map(week => ( + {weekNumbers && {weekOfYear(week[0])}} {week.map(day => ( { @@ -341,4 +342,16 @@ describe("duet-date-picker/date-utils", () => { assertMonth(getViewOfMonth(new Date(2020, 11, 10)), [30, ...range(1, 31), ...range(1, 3)]) }) }) + + describe("weekOfYear", () => { + it("returns the week number of given date", () => { + expect(weekOfYear(new Date(2019, 11, 24))).toEqual(52) + expect(weekOfYear(new Date(2019, 11, 31))).toEqual(1) + expect(weekOfYear(new Date(2020, 0, 1))).toEqual(1) + expect(weekOfYear(new Date(2020, 11, 24))).toEqual(52) + expect(weekOfYear(new Date(2020, 11, 31))).toEqual(53) + expect(weekOfYear(new Date(2021, 0, 3))).toEqual(53) + expect(weekOfYear(new Date(2021, 0, 4))).toEqual(1) + }) + }) }) diff --git a/src/components/duet-date-picker/date-utils.ts b/src/components/duet-date-picker/date-utils.ts index d113014..08ec005 100644 --- a/src/components/duet-date-picker/date-utils.ts +++ b/src/components/duet-date-picker/date-utils.ts @@ -1,4 +1,5 @@ const ISO_DATE_FORMAT = /^(\d{4})-(\d{2})-(\d{2})$/ +const MILLISECONDS_IN_WEEK = 604800000 export enum DaysOfWeek { Sunday = 0, @@ -209,3 +210,21 @@ export function chr4() { export function createIdentifier(prefix) { return `${prefix}-${chr4()}${chr4()}-${chr4()}-${chr4()}-${chr4()}-${chr4()}${chr4()}${chr4()}` } + +export function weekOfYear(date: Date): number { + const givenYear = date.getFullYear() + const fourthOfJanuaryOfGivenYear = startOfWeek(new Date(givenYear, 0, 4)) + const fourthOfJanuaryOfNextYear = startOfWeek(new Date(givenYear + 1, 0, 4)) + let startYear + if (date.getTime() >= fourthOfJanuaryOfNextYear.getTime()) { + startYear = givenYear + 1 + } else if (date.getTime() >= fourthOfJanuaryOfGivenYear.getTime()) { + startYear = givenYear + } else { + startYear = givenYear - 1 + } + const start = startOfWeek(new Date(startYear, 0, 4)) + const end = startOfWeek(date) + const diff = end.getTime() - start.getTime() + return Math.round(diff / MILLISECONDS_IN_WEEK) + 1 +} diff --git a/src/components/duet-date-picker/duet-date-picker.scss b/src/components/duet-date-picker/duet-date-picker.scss index 2a698df..e46c91d 100644 --- a/src/components/duet-date-picker/duet-date-picker.scss +++ b/src/components/duet-date-picker/duet-date-picker.scss @@ -220,6 +220,13 @@ text-align: center; } +.duet-date__week { + font-family: var(--duet-font); + font-size: 0.875rem; + font-variant-numeric: tabular-nums; + font-weight: var(--duet-font-normal); +} + .duet-date__day { -moz-appearance: none; -webkit-appearance: none; diff --git a/src/components/duet-date-picker/duet-date-picker.tsx b/src/components/duet-date-picker/duet-date-picker.tsx index 2018d26..d40722d 100644 --- a/src/components/duet-date-picker/duet-date-picker.tsx +++ b/src/components/duet-date-picker/duet-date-picker.tsx @@ -179,6 +179,11 @@ export class DuetDatePicker implements ComponentInterface { */ @Prop() dateAdapter: DuetDateAdapter = isoAdapter + /** + * Should display week numbers + */ + @Prop() weeks: boolean = false + /** * Events section. */ @@ -713,6 +718,7 @@ export class DuetDatePicker implements ComponentInterface { min={minDate} max={maxDate} dateFormatter={this.dateAdapter.format} + weekNumbers={this.weeks} /> diff --git a/src/index.html b/src/index.html index 5211aae..eec77c5 100644 --- a/src/index.html +++ b/src/index.html @@ -514,6 +514,13 @@

Required atrribute

alert("Submitted") }) </script> +
+

Week numbers

+ + +
<label for="date">Choose a date</label>
+<duet-date-picker weeks identifier="date"></duet-date-picker>
+

© 2020 LocalTapiola Services Ltd /