UNPKG

@wordpress/components

Version:
331 lines (287 loc) 10.8 kB
"use strict"; 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 _dateFns = require("date-fns"); var _i18n = require("@wordpress/i18n"); var _baseControl = _interopRequireDefault(require("../../base-control")); var _button = _interopRequireDefault(require("../../button")); var _buttonGroup = _interopRequireDefault(require("../../button-group")); var _timezone = _interopRequireDefault(require("./timezone")); var _styles = require("./styles"); var _hStack = require("../../h-stack"); var _spacer = require("../../spacer"); var _actions = require("../../input-control/reducer/actions"); var _utils = require("../utils"); var _constants = require("../constants"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ function from12hTo24h(hours, isPm) { return isPm ? (hours % 12 + 12) % 24 : hours % 12; } /** * Creates an InputControl reducer used to pad an input so that it is always a * given width. For example, the hours and minutes inputs are padded to 2 so * that '4' appears as '04'. * * @param pad How many digits the value should be. */ function buildPadInputStateReducer(pad) { return (state, action) => { const nextState = { ...state }; if (action.type === _actions.COMMIT || action.type === _actions.PRESS_UP || action.type === _actions.PRESS_DOWN) { if (nextState.value !== undefined) { nextState.value = nextState.value.toString().padStart(pad, '0'); } } return nextState; }; } /** * TimePicker is a React component that renders a clock for time selection. * * ```jsx * import { TimePicker } from '@wordpress/components'; * import { useState } from '@wordpress/element'; * * const MyTimePicker = () => { * const [ time, setTime ] = useState( new Date() ); * * return ( * <TimePicker * currentTime={ date } * onChange={ ( newTime ) => setTime( newTime ) } * is12Hour * /> * ); * }; * ``` */ function TimePicker(_ref) { let { is12Hour, currentTime, onChange } = _ref; const [date, setDate] = (0, _element.useState)(() => // Truncate the date at the minutes, see: #15495. currentTime ? (0, _dateFns.startOfMinute)((0, _utils.inputToDate)(currentTime)) : new Date()); // Reset the state when currentTime changed. // TODO: useEffect() shouldn't be used like this, causes an unnecessary render (0, _element.useEffect)(() => { setDate(currentTime ? (0, _dateFns.startOfMinute)((0, _utils.inputToDate)(currentTime)) : new Date()); }, [currentTime]); const { day, month, year, minutes, hours, am } = (0, _element.useMemo)(() => ({ day: (0, _dateFns.format)(date, 'dd'), month: (0, _dateFns.format)(date, 'MM'), year: (0, _dateFns.format)(date, 'yyyy'), minutes: (0, _dateFns.format)(date, 'mm'), hours: (0, _dateFns.format)(date, is12Hour ? 'hh' : 'HH'), am: (0, _dateFns.format)(date, 'a') }), [date, is12Hour]); const buildNumberControlChangeCallback = method => { const callback = (value, _ref2) => { let { event } = _ref2; if (!(event.target instanceof HTMLInputElement)) { return; } if (!event.target.validity.valid) { return; } // We can safely assume value is a number if target is valid. let numberValue = Number(value); // If the 12-hour format is being used and the 'PM' period is // selected, then the incoming value (which ranges 1-12) should be // increased by 12 to match the expected 24-hour format. if (method === 'hours' && is12Hour) { numberValue = from12hTo24h(numberValue, am === 'PM'); } const newDate = (0, _dateFns.set)(date, { [method]: numberValue }); setDate(newDate); onChange === null || onChange === void 0 ? void 0 : onChange((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT)); }; return callback; }; function buildAmPmChangeCallback(value) { return () => { if (am === value) { return; } const parsedHours = parseInt(hours, 10); const newDate = (0, _dateFns.setHours)(date, from12hTo24h(parsedHours, value === 'PM')); setDate(newDate); onChange === null || onChange === void 0 ? void 0 : onChange((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT)); }; } const dayField = (0, _element.createElement)(_styles.DayInput, { className: "components-datetime__time-field components-datetime__time-field-day" // Unused, for backwards compatibility. , label: (0, _i18n.__)('Day'), hideLabelFromVision: true, __next36pxDefaultSize: true, value: day, step: 1, min: 1, max: 31, required: true, spinControls: "none", isPressEnterToChange: true, isDragEnabled: false, isShiftStepEnabled: false, onChange: buildNumberControlChangeCallback('date') }); const monthField = (0, _element.createElement)(_styles.MonthSelectWrapper, null, (0, _element.createElement)(_styles.MonthSelect, { className: "components-datetime__time-field components-datetime__time-field-month" // Unused, for backwards compatibility. , label: (0, _i18n.__)('Month'), hideLabelFromVision: true, __nextHasNoMarginBottom: true, value: month, options: [{ value: '01', label: (0, _i18n.__)('January') }, { value: '02', label: (0, _i18n.__)('February') }, { value: '03', label: (0, _i18n.__)('March') }, { value: '04', label: (0, _i18n.__)('April') }, { value: '05', label: (0, _i18n.__)('May') }, { value: '06', label: (0, _i18n.__)('June') }, { value: '07', label: (0, _i18n.__)('July') }, { value: '08', label: (0, _i18n.__)('August') }, { value: '09', label: (0, _i18n.__)('September') }, { value: '10', label: (0, _i18n.__)('October') }, { value: '11', label: (0, _i18n.__)('November') }, { value: '12', label: (0, _i18n.__)('December') }], onChange: value => { const newDate = (0, _dateFns.setMonth)(date, Number(value) - 1); setDate(newDate); onChange === null || onChange === void 0 ? void 0 : onChange((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT)); } })); return (0, _element.createElement)(_styles.Wrapper, { className: "components-datetime__time" // Unused, for backwards compatibility. }, (0, _element.createElement)(_styles.Fieldset, null, (0, _element.createElement)(_baseControl.default.VisualLabel, { as: "legend", className: "components-datetime__time-legend" // Unused, for backwards compatibility. }, (0, _i18n.__)('Time')), (0, _element.createElement)(_hStack.HStack, { className: "components-datetime__time-wrapper" // Unused, for backwards compatibility. }, (0, _element.createElement)(_styles.TimeWrapper, { className: "components-datetime__time-field components-datetime__time-field-time" // Unused, for backwards compatibility. }, (0, _element.createElement)(_styles.HoursInput, { className: "components-datetime__time-field-hours-input" // Unused, for backwards compatibility. , label: (0, _i18n.__)('Hours'), hideLabelFromVision: true, __next36pxDefaultSize: true, value: hours, step: 1, min: is12Hour ? 1 : 0, max: is12Hour ? 12 : 23, required: true, spinControls: "none", isPressEnterToChange: true, isDragEnabled: false, isShiftStepEnabled: false, onChange: buildNumberControlChangeCallback('hours'), __unstableStateReducer: buildPadInputStateReducer(2) }), (0, _element.createElement)(_styles.TimeSeparator, { className: "components-datetime__time-separator" // Unused, for backwards compatibility. , "aria-hidden": "true" }, ":"), (0, _element.createElement)(_styles.MinutesInput, { className: "components-datetime__time-field-minutes-input" // Unused, for backwards compatibility. , label: (0, _i18n.__)('Minutes'), hideLabelFromVision: true, __next36pxDefaultSize: true, value: minutes, step: 1, min: 0, max: 59, required: true, spinControls: "none", isPressEnterToChange: true, isDragEnabled: false, isShiftStepEnabled: false, onChange: buildNumberControlChangeCallback('minutes'), __unstableStateReducer: buildPadInputStateReducer(2) })), is12Hour && (0, _element.createElement)(_buttonGroup.default, { className: "components-datetime__time-field components-datetime__time-field-am-pm" // Unused, for backwards compatibility. }, (0, _element.createElement)(_button.default, { className: "components-datetime__time-am-button" // Unused, for backwards compatibility. , variant: am === 'AM' ? 'primary' : 'secondary', onClick: buildAmPmChangeCallback('AM') }, (0, _i18n.__)('AM')), (0, _element.createElement)(_button.default, { className: "components-datetime__time-pm-button" // Unused, for backwards compatibility. , variant: am === 'PM' ? 'primary' : 'secondary', onClick: buildAmPmChangeCallback('PM') }, (0, _i18n.__)('PM'))), (0, _element.createElement)(_spacer.Spacer, null), (0, _element.createElement)(_timezone.default, null))), (0, _element.createElement)(_styles.Fieldset, null, (0, _element.createElement)(_baseControl.default.VisualLabel, { as: "legend", className: "components-datetime__time-legend" // Unused, for backwards compatibility. }, (0, _i18n.__)('Date')), (0, _element.createElement)(_hStack.HStack, { className: "components-datetime__time-wrapper" // Unused, for backwards compatibility. }, is12Hour ? (0, _element.createElement)(_element.Fragment, null, monthField, dayField) : (0, _element.createElement)(_element.Fragment, null, dayField, monthField), (0, _element.createElement)(_styles.YearInput, { className: "components-datetime__time-field components-datetime__time-field-year" // Unused, for backwards compatibility. , label: (0, _i18n.__)('Year'), hideLabelFromVision: true, __next36pxDefaultSize: true, value: year, step: 1, min: 1, max: 9999, required: true, spinControls: "none", isPressEnterToChange: true, isDragEnabled: false, isShiftStepEnabled: false, onChange: buildNumberControlChangeCallback('year'), __unstableStateReducer: buildPadInputStateReducer(4) })))); } var _default = TimePicker; exports.default = _default; //# sourceMappingURL=index.js.map