1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | import * as React from "react";
|
17 | import { AbstractPureComponent2, Divider, HTMLSelect, IconSize } from "@blueprintjs/core";
|
18 | import * as Classes from "./common/classes";
|
19 | import { clone } from "./common/dateUtils";
|
20 | import { measureTextWidth } from "./common/utils";
|
21 | export class DatePickerCaption extends AbstractPureComponent2 {
|
22 | state = { monthRightOffset: 0 };
|
23 | containerElement;
|
24 | displayedMonthText;
|
25 | handleMonthSelectChange = this.dateChangeHandler((d, month) => d.setMonth(month), this.props.onMonthChange);
|
26 | handleYearSelectChange = this.dateChangeHandler((d, year) => d.setFullYear(year), this.props.onYearChange);
|
27 | render() {
|
28 | const { date, locale, localeUtils, minDate, maxDate, months = localeUtils.getMonths(locale) } = this.props;
|
29 | const minYear = minDate.getFullYear();
|
30 | const maxYear = maxDate.getFullYear();
|
31 | const displayMonth = date.getMonth();
|
32 | const displayYear = date.getFullYear();
|
33 |
|
34 | const startMonth = displayYear === minYear ? minDate.getMonth() : 0;
|
35 | const endMonth = displayYear === maxYear ? maxDate.getMonth() + 1 : undefined;
|
36 | const monthOptionElements = months
|
37 | .map((month, i) => ({ label: month, value: i }))
|
38 | .slice(startMonth, endMonth);
|
39 | const years = [minYear];
|
40 | for (let year = minYear + 1; year <= maxYear; ++year) {
|
41 | years.push(year);
|
42 | }
|
43 |
|
44 | if (displayYear > maxYear) {
|
45 | years.push({ value: displayYear, disabled: true });
|
46 | }
|
47 | this.displayedMonthText = months[displayMonth];
|
48 | const monthSelect = (React.createElement(HTMLSelect, { "aria-label": "Month", iconProps: { style: { right: this.state.monthRightOffset } }, className: Classes.DATEPICKER_MONTH_SELECT, key: "month", minimal: true, onChange: this.handleMonthSelectChange, value: displayMonth, options: monthOptionElements }));
|
49 | const yearSelect = (React.createElement(HTMLSelect, { "aria-label": "Year", className: Classes.DATEPICKER_YEAR_SELECT, key: "year", minimal: true, onChange: this.handleYearSelectChange, value: displayYear, options: years }));
|
50 | const orderedSelects = this.props.reverseMonthAndYearMenus
|
51 | ? [yearSelect, monthSelect]
|
52 | : [monthSelect, yearSelect];
|
53 | return (React.createElement("div", { className: this.props.classNames.caption },
|
54 | React.createElement("div", { className: Classes.DATEPICKER_CAPTION, ref: ref => (this.containerElement = ref) }, orderedSelects),
|
55 | React.createElement(Divider, null)));
|
56 | }
|
57 | componentDidMount() {
|
58 | this.requestAnimationFrame(() => this.positionArrows());
|
59 | }
|
60 | componentDidUpdate() {
|
61 | this.positionArrows();
|
62 | }
|
63 | positionArrows() {
|
64 |
|
65 | const monthTextWidth = measureTextWidth(this.displayedMonthText, Classes.DATEPICKER_CAPTION_MEASURE, this.containerElement);
|
66 | const monthSelectWidth = this.containerElement == null ? 0 : this.containerElement.firstElementChild.clientWidth;
|
67 | const rightOffset = Math.max(2, monthSelectWidth - monthTextWidth - IconSize.STANDARD - 2);
|
68 | this.setState({ monthRightOffset: rightOffset });
|
69 | }
|
70 | dateChangeHandler(updater, handler) {
|
71 | return (e) => {
|
72 | const value = parseInt(e.target.value, 10);
|
73 |
|
74 | if (isNaN(value)) {
|
75 | return;
|
76 | }
|
77 | const newDate = clone(this.props.date);
|
78 | updater(newDate, value);
|
79 | this.props.onDateChange?.(newDate);
|
80 | handler?.(value);
|
81 | };
|
82 | }
|
83 | }
|
84 |
|
\ | No newline at end of file |