@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
160 lines • 12.7 kB
JavaScript
;
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DatePicker = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
/* eslint-disable @typescript-eslint/naming-convention */
/**
*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const date_fns_1 = require("date-fns");
const react_1 = require("react");
const react_datepicker_1 = __importDefault(require("react-datepicker"));
const defaultImports_1 = require("../_common/defaultImports");
const dialog_1 = require("../dialog");
const divider_1 = require("../divider");
const helpers_1 = require("../helpers");
const icon_button_1 = require("../icon-button");
const icons_1 = require("../icons");
const text_input_1 = require("../text-input");
const time_picker_1 = require("../time-picker");
const typography_1 = require("../typography");
const utils_1 = require("./utils");
// This wrapper is needed due to react-datepicker injecting html attributes
// into the custom input component on root level, since we use htmlAttributes
// we need to help spread them there instead of the root level
const DatePickerTextInputWrapper = (0, helpers_1.forwardRef)(function DatePickerTextInputWrapper(_a, ref) {
var { datetimeRef, textInputProps, isDisabled } = _a, reactDatePickerInjectedProps = __rest(_a, ["datetimeRef", "textInputProps", "isDisabled"]);
return ((0, jsx_runtime_1.jsx)(text_input_1.TextInput, Object.assign({ ref: ref, "aria-label": "Date picker input", rightElement: (0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { ariaLabel: "Open date picker", isClean: true, onClick: (e) => {
var _a, _b;
e.preventDefault();
e.stopPropagation();
if ((_a = datetimeRef.current) === null || _a === void 0 ? void 0 : _a.isCalendarOpen()) {
datetimeRef.current.setOpen(false);
}
else {
(_b = datetimeRef.current) === null || _b === void 0 ? void 0 : _b.setOpen(true);
}
}, children: (0, jsx_runtime_1.jsx)(icons_1.CalendarDaysIconOutline, {}) }) }, textInputProps, { isDisabled: isDisabled,
// react-datepicker injects html attributes into the custom input
htmlAttributes: Object.assign(Object.assign({}, textInputProps === null || textInputProps === void 0 ? void 0 : textInputProps.htmlAttributes), reactDatePickerInjectedProps) })));
});
exports.DatePicker = (0, helpers_1.forwardRef)(function DatePicker(props, ref) {
var _a;
const { reactDatePickerProps, textInputProps, timePickerProps, isDisabled, className, } = props;
const classes = (0, defaultImports_1.classNames)(`ndl-datepicker`, className, {});
const datetimeRef = (0, react_1.useRef)(null);
const [picker, setPicker] = (0, react_1.useState)('day');
const [preSelectedDate, setPreSelectedDate] = (0, react_1.useState)((_a = reactDatePickerProps.selected) !== null && _a !== void 0 ? _a : reactDatePickerProps.startDate);
const isInsideDialog = (0, dialog_1.useIsInsideDialog)();
const headerAction = (0, react_1.useCallback)((action) => {
setPicker(picker === action ? 'day' : action);
}, [picker]);
const CustomHeader = (0, react_1.useCallback)((props) => {
const { decreaseMonth, increaseMonth, increaseYear, decreaseYear, nextMonthButtonDisabled, nextYearButtonDisabled, prevMonthButtonDisabled, prevYearButtonDisabled, } = props;
const prevCallback = picker === 'year' ? decreaseYear : decreaseMonth;
const nextCallback = picker === 'year' ? increaseYear : increaseMonth;
const prevDisabled = picker === 'year' ? prevYearButtonDisabled : prevMonthButtonDisabled;
const nextDisabled = picker === 'year' ? nextYearButtonDisabled : nextMonthButtonDisabled;
return ((0, jsx_runtime_1.jsxs)("div", { className: "ndl-datepicker-header", children: [(0, jsx_runtime_1.jsxs)("div", { className: "ndl-datepicker-selects", children: [picker !== 'year' && ((0, jsx_runtime_1.jsx)("button", { "aria-label": `${picker === 'month' ? 'Close' : 'Open'} month picker`, "aria-pressed": picker === 'month', onClick: () => headerAction('month'), children: (0, jsx_runtime_1.jsxs)("div", { className: "n-flex n-items-center n-gap-token-3", children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: "subheading-small", children: (0, date_fns_1.format)(props.date, 'MMM') }), (0, jsx_runtime_1.jsx)(icons_1.ChevronDownIconOutline, { className: (0, defaultImports_1.classNames)('ndl-datepicker-chevron', {
'n-rotate-180': picker === 'month',
}), "aria-label": "Chevron icon" })] }) })), picker !== 'month' && ((0, jsx_runtime_1.jsx)("button", { "aria-label": `${picker === 'year' ? 'Close' : 'Open'} year picker`, onClick: () => headerAction('year'), children: (0, jsx_runtime_1.jsxs)("div", { className: "n-flex n-items-center n-gap-token-3", children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: "subheading-small", children: picker === 'year'
? (0, utils_1.getYearsPeriodString)(props.date, reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.yearItemNumber)
: (0, date_fns_1.format)(props.date, 'yyyy') }), (0, jsx_runtime_1.jsx)(icons_1.ChevronDownIconOutline, { className: (0, defaultImports_1.classNames)('ndl-datepicker-chevron', {
'n-rotate-180': picker === 'year',
}), "aria-label": "Chevron icon" })] }) }))] }), picker !== 'month' && ((0, jsx_runtime_1.jsxs)("div", { className: "n-flex n-justify-center n-gap-token-6", children: [(0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { ariaLabel: "Previous period", isClean: true, onClick: prevCallback, isDisabled: prevDisabled, className: "n-text-palette-neutral-text-default;", size: "small", children: (0, jsx_runtime_1.jsx)(icons_1.ArrowLeftIconOutline, {}) }), (0, jsx_runtime_1.jsx)(icon_button_1.IconButton, { ariaLabel: "Next period", isClean: true, onClick: nextCallback, isDisabled: nextDisabled, className: "n-text-palette-neutral-text-default;", size: "small", children: (0, jsx_runtime_1.jsx)(icons_1.ArrowRightIconOutline, {}) })] }))] }));
}, [picker, headerAction, reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.yearItemNumber]);
const handleTimeChange = (newTime) => {
if (reactDatePickerProps.selectsRange ||
reactDatePickerProps.selectsMultiple) {
// this is consistent with the behavior of react-datepicker
return;
}
const newDate = new Date(preSelectedDate !== null && preSelectedDate !== void 0 ? preSelectedDate : '');
newDate.setHours(newTime.hour, newTime.minute, 0, 0);
setPreSelectedDate(newDate);
reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.onChange(newDate, undefined);
};
/**
* Intercept onChange so we can work with
* Month and Year pickers
*/
const interceptedChange = (0, react_1.useCallback)((...args) => {
if (picker !== 'day') {
// setTimeout to prevent picker change before the handleMonthChange logic
setTimeout(() => {
setPicker('day');
});
}
else if (picker === 'day') {
if (args[0] instanceof Date) {
setPreSelectedDate(args[0]);
}
else if (args[0] !== null) {
setPreSelectedDate(args[0][0]);
}
reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.onChange(...args);
}
}, [picker, reactDatePickerProps]);
/**
* Intercept onCalendarClose so we can
* switch to "day" picker if we close on "month" or "year"
* view
*/
const interceptedOnCalendarClose = (0, react_1.useCallback)(() => {
var _a;
if (picker !== 'day') {
setPicker('day');
}
(_a = reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.onCalendarClose) === null || _a === void 0 ? void 0 : _a.call(reactDatePickerProps);
}, [picker, reactDatePickerProps]);
const handleMonthChange = (0, react_1.useCallback)((date) => {
var _a, _b, _c, _d, _e;
if (picker === 'month') {
const selectedDay = (_a = preSelectedDate === null || preSelectedDate === void 0 ? void 0 : preSelectedDate.getDate()) !== null && _a !== void 0 ? _a : 1;
const daysInNewMonth = (0, utils_1.daysInMonth)(date.getMonth(), date.getFullYear());
date.setDate(Math.min(selectedDay, daysInNewMonth));
(_b = reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.onMonthChange) === null || _b === void 0 ? void 0 : _b.call(reactDatePickerProps, date);
}
else if (picker === 'year') {
const selectedDay = (_c = preSelectedDate === null || preSelectedDate === void 0 ? void 0 : preSelectedDate.getDate()) !== null && _c !== void 0 ? _c : 1;
const selectedMonth = (_d = preSelectedDate === null || preSelectedDate === void 0 ? void 0 : preSelectedDate.getMonth()) !== null && _d !== void 0 ? _d : 0;
const daysInNewMonth = (0, utils_1.daysInMonth)(selectedMonth, date.getFullYear());
date.setMonth(selectedMonth, Math.min(selectedDay, daysInNewMonth));
(_e = reactDatePickerProps === null || reactDatePickerProps === void 0 ? void 0 : reactDatePickerProps.onMonthChange) === null || _e === void 0 ? void 0 : _e.call(reactDatePickerProps, date);
}
setPreSelectedDate(date);
}, [picker, preSelectedDate, reactDatePickerProps]);
return ((0, jsx_runtime_1.jsx)("div", { className: classes, children: (0, jsx_runtime_1.jsx)(react_datepicker_1.default, Object.assign({ ref: datetimeRef, customInput: (0, jsx_runtime_1.jsx)(DatePickerTextInputWrapper, { ref: ref, datetimeRef: datetimeRef, isDisabled: isDisabled, textInputProps: textInputProps }), customTimeInput: (0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)(divider_1.Divider, { className: "n-my-4" }), (0, jsx_runtime_1.jsx)(time_picker_1.TimePicker, Object.assign({ isFluid: true, selected: new time_picker_1.NeedleTime(preSelectedDate === null || preSelectedDate === void 0 ? void 0 : preSelectedDate.getHours(), preSelectedDate === null || preSelectedDate === void 0 ? void 0 : preSelectedDate.getMinutes()), onChange: handleTimeChange }, timePickerProps, { floatingStrategy: "absolute" }))] }), disabled: isDisabled, showPopperArrow: false, showMonthYearPicker: picker === 'month', showYearPicker: picker === 'year', shouldCloseOnSelect: picker === 'day' && !reactDatePickerProps.showTimeInput, dayClassName: () => 'ndl-datepicker-day', renderCustomHeader: CustomHeader }, reactDatePickerProps, { popperProps: Object.assign({ strategy: isInsideDialog ? 'fixed' : 'absolute' }, reactDatePickerProps.popperProps), onChange: interceptedChange, onMonthChange: handleMonthChange, onCalendarClose: interceptedOnCalendarClose })) }));
});
//# sourceMappingURL=DatePicker.js.map