@wordpress/components
Version:
UI components for WordPress.
269 lines (241 loc) • 9.26 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TimePicker = TimePicker;
exports.default = void 0;
var _element = require("@wordpress/element");
var _classnames = _interopRequireDefault(require("classnames"));
var _lodash = require("lodash");
var _moment = _interopRequireDefault(require("moment"));
var _i18n = require("@wordpress/i18n");
var _button = _interopRequireDefault(require("../button"));
var _buttonGroup = _interopRequireDefault(require("../button-group"));
var _timezone = _interopRequireDefault(require("./timezone"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* Module Constants
*/
const TIMEZONELESS_FORMAT = 'YYYY-MM-DDTHH:mm:ss';
/**
* <UpdateOnBlurAsIntegerField>
* A shared component to parse, validate, and handle remounting of the underlying form field element like <input> and <select>.
*
* @param {Object} props Component props.
* @param {string} props.as Render the component as specific element tag, defaults to "input".
* @param {number|string} props.value The default value of the component which will be parsed to integer.
* @param {Function} props.onUpdate Call back when blurred and validated.
*/
function UpdateOnBlurAsIntegerField({
as,
value,
onUpdate,
...props
}) {
function handleBlur(event) {
const {
target
} = event;
if (value === target.value) {
return;
}
const parsedValue = parseInt(target.value, 10); // Run basic number validation on the input.
if (!(0, _lodash.isInteger)(parsedValue) || typeof props.max !== 'undefined' && parsedValue > props.max || typeof props.min !== 'undefined' && parsedValue < props.min) {
// If validation failed, reset the value to the previous valid value.
target.value = value;
} else {
// Otherwise, it's valid, call onUpdate.
onUpdate(target.name, parsedValue);
}
}
return (0, _element.createElement)(as || 'input', {
// Re-mount the input value to accept the latest value as the defaultValue.
key: value,
defaultValue: value,
onBlur: handleBlur,
...props
});
}
/**
* <TimePicker>
*
* @typedef {Date|string|number} WPValidDateTimeFormat
*
* @param {Object} props Component props.
* @param {boolean} props.is12Hour Should the time picker showed in 12 hour format or 24 hour format.
* @param {WPValidDateTimeFormat} props.currentTime The initial current time the time picker should render.
* @param {Function} props.onChange Callback function when the date changed.
*/
function TimePicker({
is12Hour,
currentTime,
onChange
}) {
const [date, setDate] = (0, _element.useState)(() => // Truncate the date at the minutes, see: #15495.
(0, _moment.default)(currentTime).startOf('minutes')); // Reset the state when currentTime changed.
(0, _element.useEffect)(() => {
setDate(currentTime ? (0, _moment.default)(currentTime).startOf('minutes') : (0, _moment.default)());
}, [currentTime]);
const {
day,
month,
year,
minutes,
hours,
am
} = (0, _element.useMemo)(() => ({
day: date.format('DD'),
month: date.format('MM'),
year: date.format('YYYY'),
minutes: date.format('mm'),
hours: date.format(is12Hour ? 'hh' : 'HH'),
am: date.format('H') <= 11 ? 'AM' : 'PM'
}), [date, is12Hour]);
/**
* Function that sets the date state and calls the onChange with a new date.
* The date is truncated at the minutes.
*
* @param {Object} newDate The date object.
*/
function changeDate(newDate) {
setDate(newDate);
onChange(newDate.format(TIMEZONELESS_FORMAT));
}
function update(name, value) {
// Clone the date and call the specific setter function according to `name`.
const newDate = date.clone()[name](value);
changeDate(newDate);
}
function updateAmPm(value) {
return () => {
if (am === value) {
return;
}
const parsedHours = parseInt(hours, 10);
const newDate = date.clone().hours(value === 'PM' ? (parsedHours % 12 + 12) % 24 : parsedHours % 12);
changeDate(newDate);
};
}
const dayFormat = (0, _element.createElement)("div", {
className: "components-datetime__time-field components-datetime__time-field-day"
}, (0, _element.createElement)(UpdateOnBlurAsIntegerField, {
"aria-label": (0, _i18n.__)('Day'),
className: "components-datetime__time-field-day-input",
type: "number" // The correct function to call in moment.js is "date" not "day".
,
name: "date",
value: day,
step: 1,
min: 1,
max: 31,
onUpdate: update
}));
const monthFormat = (0, _element.createElement)("div", {
className: "components-datetime__time-field components-datetime__time-field-month"
}, (0, _element.createElement)(UpdateOnBlurAsIntegerField, {
as: "select",
"aria-label": (0, _i18n.__)('Month'),
className: "components-datetime__time-field-month-select",
name: "month",
value: month // The value starts from 0, so we have to -1 when setting month.
,
onUpdate: (key, value) => update(key, value - 1)
}, (0, _element.createElement)("option", {
value: "01"
}, (0, _i18n.__)('January')), (0, _element.createElement)("option", {
value: "02"
}, (0, _i18n.__)('February')), (0, _element.createElement)("option", {
value: "03"
}, (0, _i18n.__)('March')), (0, _element.createElement)("option", {
value: "04"
}, (0, _i18n.__)('April')), (0, _element.createElement)("option", {
value: "05"
}, (0, _i18n.__)('May')), (0, _element.createElement)("option", {
value: "06"
}, (0, _i18n.__)('June')), (0, _element.createElement)("option", {
value: "07"
}, (0, _i18n.__)('July')), (0, _element.createElement)("option", {
value: "08"
}, (0, _i18n.__)('August')), (0, _element.createElement)("option", {
value: "09"
}, (0, _i18n.__)('September')), (0, _element.createElement)("option", {
value: "10"
}, (0, _i18n.__)('October')), (0, _element.createElement)("option", {
value: "11"
}, (0, _i18n.__)('November')), (0, _element.createElement)("option", {
value: "12"
}, (0, _i18n.__)('December'))));
const dayMonthFormat = is12Hour ? (0, _element.createElement)(_element.Fragment, null, dayFormat, monthFormat) : (0, _element.createElement)(_element.Fragment, null, monthFormat, dayFormat);
return (0, _element.createElement)("div", {
className: (0, _classnames.default)('components-datetime__time')
}, (0, _element.createElement)("fieldset", null, (0, _element.createElement)("legend", {
className: "components-datetime__time-legend invisible"
}, (0, _i18n.__)('Date')), (0, _element.createElement)("div", {
className: "components-datetime__time-wrapper"
}, dayMonthFormat, (0, _element.createElement)("div", {
className: "components-datetime__time-field components-datetime__time-field-year"
}, (0, _element.createElement)(UpdateOnBlurAsIntegerField, {
"aria-label": (0, _i18n.__)('Year'),
className: "components-datetime__time-field-year-input",
type: "number",
name: "year",
step: 1,
min: 0,
max: 9999,
value: year,
onUpdate: update
})))), (0, _element.createElement)("fieldset", null, (0, _element.createElement)("legend", {
className: "components-datetime__time-legend invisible"
}, (0, _i18n.__)('Time')), (0, _element.createElement)("div", {
className: "components-datetime__time-wrapper"
}, (0, _element.createElement)("div", {
className: "components-datetime__time-field components-datetime__time-field-time"
}, (0, _element.createElement)(UpdateOnBlurAsIntegerField, {
"aria-label": (0, _i18n.__)('Hours'),
className: "components-datetime__time-field-hours-input",
type: "number",
name: "hours",
step: 1,
min: is12Hour ? 1 : 0,
max: is12Hour ? 12 : 23,
value: hours,
onUpdate: update
}), (0, _element.createElement)("span", {
className: "components-datetime__time-separator",
"aria-hidden": "true"
}, ":"), (0, _element.createElement)(UpdateOnBlurAsIntegerField, {
"aria-label": (0, _i18n.__)('Minutes'),
className: "components-datetime__time-field-minutes-input",
type: "number",
name: "minutes",
step: 1,
min: 0,
max: 59,
value: minutes,
onUpdate: update
})), is12Hour && (0, _element.createElement)(_buttonGroup.default, {
className: "components-datetime__time-field components-datetime__time-field-am-pm"
}, (0, _element.createElement)(_button.default, {
isPrimary: am === 'AM',
isSecondary: am !== 'AM',
onClick: updateAmPm('AM'),
className: "components-datetime__time-am-button"
}, (0, _i18n.__)('AM')), (0, _element.createElement)(_button.default, {
isPrimary: am === 'PM',
isSecondary: am !== 'PM',
onClick: updateAmPm('PM'),
className: "components-datetime__time-pm-button"
}, (0, _i18n.__)('PM'))), (0, _element.createElement)(_timezone.default, null))));
}
var _default = TimePicker;
exports.default = _default;
//# sourceMappingURL=time.js.map