@wordpress/components
Version:
UI components for WordPress.
288 lines (280 loc) • 9.01 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TimePicker = TimePicker;
exports.default = void 0;
var _dateFns = require("date-fns");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _baseControl = _interopRequireDefault(require("../../base-control"));
var _visuallyHidden = require("../../visually-hidden");
var _selectControl = _interopRequireDefault(require("../../select-control"));
var _timezone = _interopRequireDefault(require("./timezone"));
var _styles = require("./styles");
var _hStack = require("../../h-stack");
var _spacer = require("../../spacer");
var _utils = require("../utils");
var _constants = require("../constants");
var _timeInput = require("./time-input");
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
const VALID_DATE_ORDERS = ['dmy', 'mdy', 'ymd'];
/**
* 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({
is12Hour,
currentTime,
onChange,
dateOrder: dateOrderProp,
hideLabelFromVision = false
}) {
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 monthOptions = [{
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')
}];
const {
day,
month,
year,
minutes,
hours
} = (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, 'HH'),
am: (0, _dateFns.format)(date, 'a')
}), [date]);
const buildNumberControlChangeCallback = method => {
const callback = (value, {
event
}) => {
if (!(0, _utils.validateInputElementTarget)(event)) {
return;
}
// We can safely assume value is a number if target is valid.
const numberValue = Number(value);
const newDate = (0, _dateFns.set)(date, {
[method]: numberValue
});
setDate(newDate);
onChange?.((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT));
};
return callback;
};
const onTimeInputChangeCallback = ({
hours: newHours,
minutes: newMinutes
}) => {
const newDate = (0, _dateFns.set)(date, {
hours: newHours,
minutes: newMinutes
});
setDate(newDate);
onChange?.((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT));
};
const dayField = /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.DayInput, {
className: "components-datetime__time-field components-datetime__time-field-day" // Unused, for backwards compatibility.
,
label: (0, _i18n.__)('Day'),
hideLabelFromVision: true,
__next40pxDefaultSize: true,
value: day,
step: 1,
min: 1,
max: 31,
required: true,
spinControls: "none",
isPressEnterToChange: true,
isDragEnabled: false,
isShiftStepEnabled: false,
onChange: buildNumberControlChangeCallback('date')
}, "day");
const monthField = /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.MonthSelectWrapper, {
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_selectControl.default, {
className: "components-datetime__time-field components-datetime__time-field-month" // Unused, for backwards compatibility.
,
label: (0, _i18n.__)('Month'),
hideLabelFromVision: true,
__next40pxDefaultSize: true,
__nextHasNoMarginBottom: true,
value: month,
options: monthOptions,
onChange: value => {
const newDate = (0, _dateFns.setMonth)(date, Number(value) - 1);
setDate(newDate);
onChange?.((0, _dateFns.format)(newDate, _constants.TIMEZONELESS_FORMAT));
}
})
}, "month");
const yearField = /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.YearInput, {
className: "components-datetime__time-field components-datetime__time-field-year" // Unused, for backwards compatibility.
,
label: (0, _i18n.__)('Year'),
hideLabelFromVision: true,
__next40pxDefaultSize: true,
value: year,
step: 1,
min: 1,
max: 9999,
required: true,
spinControls: "none",
isPressEnterToChange: true,
isDragEnabled: false,
isShiftStepEnabled: false,
onChange: buildNumberControlChangeCallback('year'),
__unstableStateReducer: (0, _utils.buildPadInputStateReducer)(4)
}, "year");
const defaultDateOrder = is12Hour ? 'mdy' : 'dmy';
const dateOrder = dateOrderProp && VALID_DATE_ORDERS.includes(dateOrderProp) ? dateOrderProp : defaultDateOrder;
const fields = dateOrder.split('').map(field => {
switch (field) {
case 'd':
return dayField;
case 'm':
return monthField;
case 'y':
return yearField;
default:
return null;
}
});
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Wrapper, {
className: "components-datetime__time" // Unused, for backwards compatibility.
,
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Fieldset, {
children: [hideLabelFromVision ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_visuallyHidden.VisuallyHidden, {
as: "legend",
children: (0, _i18n.__)('Time')
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_baseControl.default.VisualLabel, {
as: "legend",
className: "components-datetime__time-legend" // Unused, for backwards compatibility.
,
children: (0, _i18n.__)('Time')
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_hStack.HStack, {
className: "components-datetime__time-wrapper" // Unused, for backwards compatibility.
,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_timeInput.TimeInput, {
value: {
hours: Number(hours),
minutes: Number(minutes)
},
is12Hour: is12Hour,
onChange: onTimeInputChangeCallback
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_spacer.Spacer, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_timezone.default, {})]
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Fieldset, {
children: [hideLabelFromVision ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_visuallyHidden.VisuallyHidden, {
as: "legend",
children: (0, _i18n.__)('Date')
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_baseControl.default.VisualLabel, {
as: "legend",
className: "components-datetime__time-legend" // Unused, for backwards compatibility.
,
children: (0, _i18n.__)('Date')
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_hStack.HStack, {
className: "components-datetime__time-wrapper" // Unused, for backwards compatibility.
,
children: fields
})]
})]
});
}
/**
* A component to input a time.
*
* Values are passed as an object in 24-hour format (`{ hours: number, minutes: number }`).
*
* ```jsx
* import { TimePicker } from '@wordpress/components';
* import { useState } from '@wordpress/element';
*
* const MyTimeInput = () => {
* const [ time, setTime ] = useState( { hours: 13, minutes: 30 } );
*
* return (
* <TimePicker.TimeInput
* value={ time }
* onChange={ setTime }
* label="Time"
* />
* );
* };
* ```
*/
TimePicker.TimeInput = _timeInput.TimeInput;
Object.assign(TimePicker.TimeInput, {
displayName: 'TimePicker.TimeInput'
});
var _default = exports.default = TimePicker;
//# sourceMappingURL=index.js.map