Skip to content

Commit

Permalink
Make it possible to start the week on monday
Browse files Browse the repository at this point in the history
Signed-off-by: Grégoire Bélorgey <gregoire@jianda.fr>
Signed-off-by: Grégoire Bélorgey <gregoire@jianda.fr>
  • Loading branch information
gregoire-jianda committed May 16, 2024
1 parent e582bff commit 477a877
Show file tree
Hide file tree
Showing 22 changed files with 139 additions and 45 deletions.
4 changes: 4 additions & 0 deletions docusaurus/docs/date-picker/input-date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ The start year when the component is rendered. Defaults to `1800`.
`Type: number | undefined`
The end year when the component is rendered. Defaults to `2200`.

**startWeekOnMonday**
`Type: boolean | undefined`
Flag indicating if calendar grid sould show monday as the first column. Defaults to `false`.

**inputEnabled**
`Type: boolean | undefined`
Flag indicating if the component should be enabled or not. Behavior similarly to `disabled`. Defaults to `true`.
Expand Down
4 changes: 4 additions & 0 deletions docusaurus/docs/date-picker/multiple-dates-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ The start year when the component is rendered. Defaults to `1800`.
`Type: number | undefined`
The end year when the component is rendered. Defaults to `2200`.

**startWeekOnMonday**
`Type: boolean | undefined`
Flag indicating if calendar grid sould show monday as the first column. Defaults to `false`.

**closeIcon**
`Type: string | undefined`
The icon used to close the component. Defaults to `close`. You can pass the name of an icon from [MaterialCommunityIcons](https://materialdesignicons.com/).
Expand Down
4 changes: 4 additions & 0 deletions docusaurus/docs/date-picker/range-date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ The start year when the component is rendered. Defaults to `1800`.
`Type: number | undefined`
The end year when the component is rendered. Defaults to `2200`.

**startWeekOnMonday**
`Type: boolean | undefined`
Flag indicating if calendar grid sould show monday as the first column. Defaults to `false`.

**closeIcon**
`Type: string | undefined`
The icon used to close the component. Defaults to `close`. You can pass the name of an icon from [MaterialCommunityIcons](https://materialdesignicons.com/).
Expand Down
4 changes: 4 additions & 0 deletions docusaurus/docs/date-picker/single-date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ The start year when the component is rendered. Defaults to `1800`.
`Type: number | undefined`
The end year when the component is rendered. Defaults to `2200`.

**startWeekOnMonday**
`Type: boolean | undefined`
Flag indicating if calendar grid sould show monday as the first column. Defaults to `false`.

**closeIcon**
`Type: string | undefined`
The icon used to close the component. Defaults to `close`. You can pass the name of an icon from [MaterialCommunityIcons](https://materialdesignicons.com/).
Expand Down
1 change: 1 addition & 0 deletions example/src/ReadMeExampleMultiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default function ReadMeExampleMultiple() {
// animationType="slide" // optional, default is slide on ios/android and none on web
// startYear={2000} // optional, default is 1800
// endYear={2100} // optional, default is 2200
// startWeekOnMonday={true} // optional, default is false
/>
</>
)
Expand Down
1 change: 1 addition & 0 deletions example/src/ReadMeExampleRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default function ReadMeExampleRange() {
// animationType="slide" // optional, default is slide on ios/android and none on web
// startYear={2000} // optional, default is 1800
// endYear={2100} // optional, default is 2200
// startWeekOnMonday={true} // optional, default is false
/>
</>
)
Expand Down
1 change: 1 addition & 0 deletions example/src/ReadMeExampleSingle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default function ReadMeExampleSingle() {
// animationType="slide" // optional, default is 'slide' on ios/android and 'none' on web
// startYear={2000} // optional, default is 1800
// endYear={2100} // optional, default is 2200
// startWeekOnMonday={true} // optional, default is false
//
/>
</>
Expand Down
5 changes: 5 additions & 0 deletions src/Date/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type BaseCalendarProps = {
validRange?: ValidRangeType
startYear?: number
endYear?: number
startWeekOnMonday?: boolean

// here they are optional but in final implementation they are required
date?: CalendarDate
Expand Down Expand Up @@ -95,6 +96,7 @@ function Calendar(
dates,
validRange,
dateMode,
startWeekOnMonday,
} = props

const theme = useTheme()
Expand Down Expand Up @@ -177,6 +179,7 @@ function Calendar(
initialIndex={getInitialIndex(firstDate)}
selectedYear={selectedYear}
scrollMode={scrollMode}
startWeekOnMonday={startWeekOnMonday || false}
renderItem={({ index }) => (
<Month
locale={locale}
Expand All @@ -196,6 +199,7 @@ function Calendar(
selectColor={selectColor}
roundness={theme.roundness}
disableWeekDays={disableWeekDays}
startWeekOnMonday={startWeekOnMonday || false}
/>
)}
renderHeader={({ onPrev, onNext }) => (
Expand All @@ -205,6 +209,7 @@ function Calendar(
onNext={onNext}
scrollMode={scrollMode}
disableWeekDays={disableWeekDays}
startWeekOnMonday={startWeekOnMonday || false}
/>
)}
/>
Expand Down
8 changes: 7 additions & 1 deletion src/Date/CalendarHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ function CalendarHeader({
onNext,
disableWeekDays,
locale,
startWeekOnMonday,
}: {
locale: undefined | string
scrollMode: 'horizontal' | 'vertical'
onPrev: () => any
onNext: () => any
disableWeekDays?: DisableWeekDaysType
startWeekOnMonday: boolean
}) {
const theme = useTheme()
const isHorizontal = scrollMode === 'horizontal'
Expand Down Expand Up @@ -67,7 +69,11 @@ function CalendarHeader({
</View>
</View>
) : null}
<DayNames disableWeekDays={disableWeekDays} locale={locale} />
<DayNames
disableWeekDays={disableWeekDays}
locale={locale}
startWeekOnMonday={startWeekOnMonday}
/>
</View>
)
}
Expand Down
1 change: 1 addition & 0 deletions src/Date/DatePickerInput.shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type DatePickerInputProps = {
disableStatusBarPadding?: boolean
animationType?: 'slide' | 'fade' | 'none'
presentationStyle?: 'pageSheet' | 'overFullScreen'
startWeekOnMonday?: boolean
} & Omit<
React.ComponentProps<typeof TextInput>,
'value' | 'onChange' | 'onChangeText' | 'inputMode'
Expand Down
2 changes: 2 additions & 0 deletions src/Date/DatePickerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function DatePickerInput(
endYear,
inputEnabled,
disableStatusBarPadding,
startWeekOnMonday,
}) =>
withModal ? (
<DatePickerModal
Expand All @@ -81,6 +82,7 @@ function DatePickerInput(
animationType={animationType}
presentationStyle={presentationStyle}
label={rest.label as any}
startWeekOnMonday={startWeekOnMonday}
/>
) : null
}
Expand Down
1 change: 1 addition & 0 deletions src/Date/DatePickerInputWithoutModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function DatePickerInputWithoutModal(
endYear: DatePickerInputProps['endYear']
inputEnabled: DatePickerInputProps['inputEnabled']
disableStatusBarPadding: DatePickerInputProps['disableStatusBarPadding']
startWeekOnMonday?: DatePickerInputProps['startWeekOnMonday']
}) => any
inputButton?: React.ReactNode
},
Expand Down
2 changes: 2 additions & 0 deletions src/Date/DatePickerModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function DatePickerModalContent(
startYear,
endYear,
statusBarOnTopOfBackdrop,
startWeekOnMonday,
} = props
const anyProps = props as any

Expand Down Expand Up @@ -199,6 +200,7 @@ export function DatePickerModalContent(
dateMode={dateMode}
startYear={startYear}
endYear={endYear}
startWeekOnMonday={startWeekOnMonday}
/>
}
calendarEdit={
Expand Down
28 changes: 16 additions & 12 deletions src/Date/DayNames.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,35 @@ import { DisableWeekDaysType, showWeekDay } from './dateUtils'

export const dayNamesHeight = 44

// TODO: wait for a better Intl api ;-)
const weekdays = [
new Date(2020, 7, 2),
new Date(2020, 7, 3),
new Date(2020, 7, 4),
new Date(2020, 7, 5),
new Date(2020, 7, 6),
new Date(2020, 7, 7),
new Date(2020, 7, 8),
]

function DayNames({
disableWeekDays,
locale,
startWeekOnMonday,
}: {
locale: undefined | string
disableWeekDays?: DisableWeekDaysType
startWeekOnMonday: boolean
}) {
const theme = useTheme()
const shortDayNames = React.useMemo<string[]>(() => {
// TODO: wait for a better Intl api ;-)
const weekdays = [
new Date(2020, 7, 2),
new Date(2020, 7, 3),
new Date(2020, 7, 4),
new Date(2020, 7, 5),
new Date(2020, 7, 6),
new Date(2020, 7, 7),
new Date(2020, 7, 8),
]
if (startWeekOnMonday) {
weekdays.push(weekdays.shift() as Date)
}
const formatter = new Intl.DateTimeFormat(locale, {
weekday: 'narrow',
})
return weekdays.map((date) => formatter.format(date))
}, [locale])
}, [locale, startWeekOnMonday])

return (
<View
Expand Down
43 changes: 29 additions & 14 deletions src/Date/Month.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface BaseMonthProps {
selectColor: string
roundness: number
validRange?: ValidRangeType
startWeekOnMonday: boolean

// some of these should be required in final implementation
startDate?: CalendarDate
Expand Down Expand Up @@ -91,6 +92,7 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
disableWeekDays,
locale,
validRange,
startWeekOnMonday,
} = props
const theme = useTheme()
const textColorOnPrimary = useTextColorOnPrimary()
Expand All @@ -111,10 +113,10 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
const today = new Date()

const daysInMonth = getDaysInMonth({ year, month })
const dayOfWeek = getFirstDayOfMonth({ year, month })
const dayOfWeek = getFirstDayOfMonth({ year, month, startWeekOnMonday })
const emptyDays = dayOfWeek

return monthGrid(index).map(({ days, weekGrid }) => {
return monthGrid(index, startWeekOnMonday).map(({ days, weekGrid }) => {
return {
weekIndex: weekGrid,
generatedDays: days.map((_, dayIndex) => {
Expand Down Expand Up @@ -248,6 +250,7 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
endDate,
dates,
date,
startWeekOnMonday,
])

let textFont = theme?.isV3
Expand All @@ -263,7 +266,12 @@ function Month(props: MonthSingleProps | MonthRangeProps | MonthMultiProps) {
const iconSource = theme.isV3 ? iconSourceV3 : iconSourceV2

return (
<View style={[styles.month, { height: getMonthHeight(scrollMode, index) }]}>
<View
style={[
styles.month,
{ height: getMonthHeight(scrollMode, index, startWeekOnMonday) },
]}
>
<View
style={[
styles.monthHeader,
Expand Down Expand Up @@ -388,8 +396,8 @@ const styles = StyleSheet.create({
opacity1: { opacity: 1 },
})

const monthGrid = (index: number) => {
return Array(getGridCount(index))
const monthGrid = (index: number, startWeekOnMonday: boolean) => {
return Array(getGridCount(index, startWeekOnMonday))
.fill(null)
.map((_, weekGrid) => {
const days = Array(7).fill(null)
Expand All @@ -405,20 +413,20 @@ function getIndexCount(index: number): number {
return -(startAtIndex - index)
}

function weeksOffset(index: number): number {
function weeksOffset(index: number, startWeekOnMonday: boolean): number {
if (index === startAtIndex) {
return 0
}
let off = 0
if (index > startAtIndex) {
for (let i = 0; i < index - startAtIndex; i++) {
const cIndex = startAtIndex + i
off += gridCounts[cIndex] || getGridCount(cIndex)
off += gridCounts[cIndex] || getGridCount(cIndex, startWeekOnMonday)
}
} else {
for (let i = 0; i < startAtIndex - index; i++) {
const cIndex = startAtIndex - i - 1
off -= gridCounts[cIndex] || getGridCount(cIndex)
off -= gridCounts[cIndex] || getGridCount(cIndex, startWeekOnMonday)
}
}
return off
Expand All @@ -431,10 +439,13 @@ export function getIndexFromHorizontalOffset(
return startAtIndex + Math.floor(offset / width)
}

export function getIndexFromVerticalOffset(offset: number): number {
export function getIndexFromVerticalOffset(
offset: number,
startWeekOnMonday: boolean
): number {
let estimatedIndex = startAtIndex + Math.ceil(offset / estimatedMonthHeight)

const realOffset = getVerticalMonthsOffset(estimatedIndex)
const realOffset = getVerticalMonthsOffset(estimatedIndex, startWeekOnMonday)
const difference = (realOffset - beginOffset - offset) / estimatedMonthHeight
if (difference >= 1 || difference <= -1) {
estimatedIndex -= Math.floor(difference)
Expand All @@ -449,9 +460,12 @@ export function getHorizontalMonthOffset(index: number, width: number) {
return width * index
}

export function getVerticalMonthsOffset(index: number) {
export function getVerticalMonthsOffset(
index: number,
startWeekOnMonday: boolean
) {
const count = getIndexCount(index)
const ob = weeksOffset(index)
const ob = weeksOffset(index, startWeekOnMonday)
const monthsHeight = weekSize * ob
const c = monthsHeight + count * (dayNamesHeight + montHeaderHeight)

Expand All @@ -460,10 +474,11 @@ export function getVerticalMonthsOffset(index: number) {

export function getMonthHeight(
scrollMode: 'horizontal' | 'vertical',
index: number
index: number,
startWeekOnMonday: boolean
): number {
const calendarHeight = getCalendarHeaderHeight(scrollMode)
const gc = getGridCount(index)
const gc = getGridCount(index, startWeekOnMonday)

const currentMonthHeight = weekSize * gc
const extraHeight =
Expand Down
Loading

0 comments on commit 477a877

Please sign in to comment.