@wordpress/components
Version:
UI components for WordPress.
331 lines (287 loc) • 10.8 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 _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