diff --git a/src/Calendar.scss b/src/Calendar.scss index fd95545..d5c7920 100644 --- a/src/Calendar.scss +++ b/src/Calendar.scss @@ -1,6 +1,7 @@ @import 'bootstrap/scss/functions'; @import 'bootstrap/scss/variables'; @import 'bootstrap/scss/mixins'; +@import 'bootstrap/scss/forms'; @import 'bootstrap/scss/grid'; @import 'bootstrap/scss/buttons'; @@ -111,3 +112,20 @@ .Day-today { background: $gray-300; } + +.Calendar-month-name.input-group { + justify-content: center; + font-size: 0.75em; +} + +.Calendar-month-input { + max-width: 12.5em; +} + +.Calendar-year-input { + max-width: 6em; +} + +.Calendar-today-button { + max-width: 5em; +} diff --git a/src/Calendar.tsx b/src/Calendar.tsx index 3e20cf5..f0760b8 100644 --- a/src/Calendar.tsx +++ b/src/Calendar.tsx @@ -1,6 +1,17 @@ import React from 'react'; import './Calendar.scss'; -import {dateName, Day, decadeNames, frIsLeap, frJDN, jdnGregorian, jdnLongCount, Month, monthName} from './dates'; +import { + dateName, + Day, + decadeNames, + frIsLeap, + frJDN, + jdnFrench, + jdnGregorian, + jdnLongCount, + Month, + monthName +} from './dates'; type MonthProps = { year: number; @@ -11,13 +22,6 @@ type DateProps = MonthProps & { day: Day; }; -export type CalendarProps = MonthProps & { - todayJDN: number; - onSwitch?: (year: number, month: Month) => void, -}; - -type CalendarState = {}; - function DecadeName({name}: { name: string }): JSX.Element { return
{name}
; } @@ -61,7 +65,7 @@ function ComplementaryDay({year, month, day, todayJDN}: DateProps & { todayJDN: ; } -function ComplementaryDays({year, todayJDN}: {year: number, todayJDN: number}): JSX.Element { +function ComplementaryDays({year, todayJDN}: { year: number, todayJDN: number }): JSX.Element { return
{ Array.from(Array(frIsLeap(year) ? 6 : 5).keys()).map(i => <> @@ -70,7 +74,37 @@ function ComplementaryDays({year, todayJDN}: {year: number, todayJDN: number}): }
; } +export type CalendarProps = MonthProps & { + todayJDN: number; + onSwitch?: (year: number, month: Month) => void, +}; + +type CalendarState = { + selecting: boolean, + yearStr: string, +}; + export class Calendar extends React.Component { + selection: React.RefObject; + + constructor(props: CalendarProps) { + super(props); + this.state = { + selecting: false, + yearStr: this.props.year.toString(), + }; + this.selection = React.createRef(); + this.handleClickOutside = this.handleClickOutside.bind(this); + } + + componentDidMount() { + document.addEventListener('click', this.handleClickOutside, true); + } + + componentWillUnmount() { + document.removeEventListener('click', this.handleClickOutside, true); + } + private goToNormalized(year: number, month: number) { if (month < 1) { --year; @@ -101,6 +135,49 @@ export class Calendar extends React.Component { this.goToNormalized(this.props.year, this.props.month + 1); } + startSelection() { + this.setState({selecting: true}); + } + + handleClickOutside(event: any) { + if (this.state.selecting && this.selection.current && !this.selection.current.contains(event.target)) + this.setState({selecting: false}); + } + + handleKeyUp(event: any) { + if (event.key === 'Escape') + this.setState({selecting: false}); + } + + monthChange(event: any) { + this.props.onSwitch && this.props.onSwitch(this.props.year, event.target.value as Month); + } + + yearChange(event: any) { + console.log(/^-?\d+/.test(event.target.value)); + if (/^-?\d+/.test(event.target.value)) { + this.props.onSwitch && this.props.onSwitch(+event.target.value, this.props.month); + } + this.setState({yearStr: event.target.value}); + } + + componentDidUpdate(prevProps: CalendarProps) { + if (prevProps.year !== this.props.year) { + const yearStr = this.props.year.toString(); + if (this.state.yearStr !== yearStr) { + this.setState({ + yearStr: yearStr, + }); + } + } + } + + goToToday() { + const {year, month} = jdnFrench(this.props.todayJDN); + this.goToNormalized(year, month); + this.setState({selecting: false}); + } + render(): JSX.Element { return
@@ -112,9 +189,24 @@ export class Calendar extends React.Component { onClick={this.prevMonth.bind(this)}>‹
-
+ {!this.state.selecting &&
{this.props.month < 13 && monthName(this.props.month)} {this.props.year} -
+
} + {this.state.selecting &&
+ + + +
}
- {this.props.month < 13 && } + {this.props.month < 13 && + } {this.props.month === 13 && } ; }