react-material-time-picker
Version:
TimePicker is a user interface component that allows the user to easily select a specific time. It provides an analog clock interface that is easy to use and intuitive. TimePicker can be easily integrated into other user interface components, making it a
251 lines (249 loc) • 13.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = Analog;
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.promise.js");
require("core-js/modules/es.parse-int.js");
require("core-js/modules/es.parse-float.js");
require("core-js/modules/es.regexp.to-string.js");
var _react = _interopRequireWildcard(require("react"));
var _Clock = require("./Clock.js");
var _utilities = require("../../utilities.js");
var _ThemeContext = require("../../ThemeContext.js");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
(function () {
const styles = ".time-picker-component .clock {\n margin: 2em auto;\n box-sizing: border-box;\n border-radius: 500px;\n font-family: inherit;\n font-size: 1em;\n font-weight: 400;\n line-height: 24px;\n letter-spacing: 0.5px;\n position: relative;\n}\n.time-picker-component .clock:before {\n content: \"\";\n padding-top: 100%;\n width: 100%;\n display: block;\n}\n.time-picker-component .clock span {\n cursor: pointer;\n display: grid;\n align-items: center;\n justify-content: center;\n text-align: center;\n position: absolute;\n padding-top: -3px;\n}\n.time-picker-component .clock .test {\n position: absolute;\n border-radius: 500px;\n}\n.time-picker-component .clock .selected {\n transition: all 0.5s ease-in;\n}\n.time-picker-component .clock .center {\n position: absolute;\n border-radius: 100px;\n width: 0.5em;\n height: 0.5em;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n}\n.time-picker-component .clock .hand {\n height: 0.1em;\n width: 100%;\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n}\n.time-picker-component .clock .pointer {\n position: absolute;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: 100px;\n text-align: center;\n cursor: move;\n}\n.time-picker-component .clock .digits-clockFace {\n position: absolute;\n top: 0;\n left: 0;\n}\n.time-picker-component .clock .no-show-minutes {\n position: absolute;\n width: 1px;\n height: 1px;\n left: 9px;\n top: -9px;\n}";
const fileName = "Analog_analog";
const element = document.querySelector("style[data-sass-component='Analog_analog']");
if (!element) {
const styleBlock = document.createElement("style");
styleBlock.innerHTML = styles;
styleBlock.setAttribute("data-sass-component", fileName);
document.head.appendChild(styleBlock);
} else {
element.innerHTML = styles;
}
})();
function Analog(props) {
var _clockFace$current;
const clockFace = (0, _react.useRef)();
const hand = (0, _react.useRef)();
let animationId = 0;
const clockPos = ((_clockFace$current = clockFace.current) === null || _clockFace$current === void 0 ? void 0 : _clockFace$current.getBoundingClientRect()) || {
left: 0,
top: 0
};
const pointerFace = (0, _react.useRef)();
const digitsClockFace = (0, _react.useRef)();
const hoursClockFace = (0, _react.useMemo)(() => {
return new _Clock.Clock();
}, []);
const minutesClockFace = (0, _react.useMemo)(() => {
return new _Clock.Clock();
}, []);
const [hoursDigits, setHoursDigits] = (0, _react.useState)([]);
const [minutesDigits, setMinutesDigits] = (0, _react.useState)([]);
const [hoursPointerDigit, setHoursPointerDigit] = (0, _react.useState)(0);
const [minutesPointerDigit, setMinutesPointerDigit] = (0, _react.useState)(0);
const [radius, setRadius] = (0, _react.useState)(128);
const pageIsLoaded = (0, _react.useRef)(false);
const [colors] = (0, _ThemeContext.useTheme)();
const digits = props.mode === 'hours' ? hoursDigits : minutesDigits;
const pointer = props.mode === 'hours' ? hoursPointerDigit : minutesPointerDigit;
const setPointer = props.mode === 'hours' ? setHoursPointerDigit : setMinutesPointerDigit;
let clock = props.mode === 'hours' ? hoursClockFace : minutesClockFace;
const angelToPos = (0, _react.useCallback)(radian => {
return {
x: Math.round(Math.cos(radian) * radius),
y: Math.round(Math.sin(radian) * radius)
};
}, [radius]);
const relocatePointerByAngel = (0, _react.useCallback)(function (angel) {
let pointPlacement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
let value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
const degree = radToDegree(angel);
if (pointPlacement === null) pointPlacement = angelToPos(angel, radius);
if (value === null) value = pointer;
pointerFace.current.style.transform = "translate(" + pointPlacement.x + "px," + pointPlacement.y + "px)";
pointerFace.current.innerHTML = props.mode === 'hours' ? value === 0 ? 12 : value : value;
hand.current.style.transform = "rotate(" + degree + "deg)";
}, [angelToPos, pointer, props.mode, radius]);
const relocatePointerByIndex = (0, _react.useCallback)(idx => {
if (digits.length === 0) return;
let point = digits[idx].placement;
const rad = clock.angel(idx);
relocatePointerByAngel(rad, point, idx);
}, [clock, digits, relocatePointerByAngel]);
const shortestPath = (0, _react.useCallback)((start, dest) => {
let path;
let difference = dest - start;
let distance;
const fullClock = props.mode === 'minutes' ? 60 : 12;
if (difference > 0 && difference < fullClock / 2 || fullClock - start + dest <= fullClock / 2) {
distance = difference > 0 ? difference : fullClock - start + dest;
path = clock.goClockwise(start, distance);
} else {
distance = Math.abs(dest - start) >= fullClock / 2 ? fullClock - dest + start : start - dest;
path = clock.goCounterClockwise(start, distance);
}
return path;
}, [props.mode, clock]);
const handleAnimatedRelocation = (0, _react.useCallback)(destIdx => {
const start = props.mode === 'hours' ? pointer % 12 : pointer;
const path = shortestPath(start, destIdx);
const waitTime = 300 / path.length;
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function loop(counter) {
if (counter >= path.length) {
setPointer(destIdx);
return;
}
await relocatePointerByIndex(path[counter].value);
await wait(waitTime);
requestAnimationFrame(() => {
loop(counter + 1);
});
}
loop(0);
}, [pointer, props.mode, relocatePointerByIndex, setPointer, shortestPath]);
const drawClock = (0, _react.useCallback)((radius, offset) => {
hoursClockFace.draw(radius, 12);
minutesClockFace.draw(radius, 60);
setHoursDigits(hoursClockFace.getDigits());
setMinutesDigits(minutesClockFace.getDigits());
const clockFaceElement = digitsClockFace.current;
const pointerElement = pointerFace.current;
pointerElement.style.width = offset * 3 + 'px';
pointerElement.style.height = offset * 3 + 'px';
pointerElement.style.top = radius - offset + 'px';
pointerElement.style.left = radius - offset + 'px';
clockFaceElement.style.transform = 'translate(' + radius + 'px,' + radius + 'px)';
}, [hoursClockFace, minutesClockFace]);
function radToDegree(rad) {
return rad * 180 / Math.PI;
}
function getAngel(x, y) {
const rad = Math.atan2(y, x);
return Math.round(rad * 100) / 100;
}
function getAngelByIndex(idx) {
const numberOfUnits = props.mode === 'hours' ? 12 : 60;
if (idx >= 0 && idx < numberOfUnits) {
return getAngel(digits[idx].placement.x, digits[idx].placement.y);
}
}
function handleDrag(e) {
let mousePos;
let angel = getAngelByIndex(pointer); //the last position of the hand clock
function handleRelease() {
window.removeEventListener('mousemove', startAnimation);
window.removeEventListener('mouseup', handleRelease);
let closestDigit = clock.getTheClosestDigit(angel);
setPointer(closestDigit);
setGlobalTime(closestDigit);
relocatePointerByIndex(closestDigit);
}
function startAnimation(e) {
if (animationId) cancelAnimationFrame(animationId);
animationId = requestAnimationFrame(() => trackMouse(e));
}
function trackMouse(e) {
mousePos = getPosFromClockCenter(e.clientX, e.clientY);
angel = getAngel(mousePos.x, mousePos.y);
relocatePointerByAngel(angel, null, clock.getTheClosestDigit(angel));
}
e.preventDefault();
window.addEventListener("mousemove", startAnimation);
window.addEventListener('mouseup', handleRelease);
}
function getPosFromClockCenter(xPosFromDoc, yPosFromDoc) {
let posFromParent = {};
posFromParent.x = xPosFromDoc - clockPos.left - radius;
posFromParent.y = yPosFromDoc - clockPos.top - radius;
return posFromParent;
}
function handleAutoRelocate(index) {
handleAnimatedRelocation(index);
setGlobalTime(index);
}
function setGlobalTime(newTime) {
let time = (0, _utilities.decode)(props.time);
props.mode === 'hours' ? props.onChange("".concat(props.dayMode === 'pm' ? parseInt(newTime) + 12 : (0, _utilities.normalize)(newTime)).concat(time.minute)) : props.onChange("".concat(time.hour).concat((0, _utilities.normalize)(newTime)));
}
const getGlobalTime = (0, _react.useCallback)(mode => {
const time = (0, _utilities.decode)(props.time);
return mode === 'hours' ? parseInt(time.hour % 12) : parseInt(time.minute);
}, [props.time]);
(0, _react.useEffect)(() => {
if (typeof props.time !== 'undefined' && digits.length > 0) {
const digit = getGlobalTime(props.mode);
if (digit !== pointer) {
handleAnimatedRelocation(digit);
}
}
}, [props.time, props.mode, digits.length, getGlobalTime, handleAnimatedRelocation, pointer]);
(0, _react.useEffect)(() => {
if (typeof clockFace.current !== 'undefined') {
var _clockFace$current2;
const diameter = (_clockFace$current2 = clockFace.current) === null || _clockFace$current2 === void 0 ? void 0 : _clockFace$current2.getBoundingClientRect().width;
const offset = parseFloat(window.getComputedStyle(clockFace.current, null).getPropertyValue('font-size'));
const radius = Math.round(diameter - offset - 2 * offset / (diameter / 4)) / 2;
setRadius(radius);
drawClock(radius, offset);
}
}, [clockFace, drawClock]);
(0, _react.useEffect)(() => {
if (digits.length > 0 && pageIsLoaded.current === false) {
relocatePointerByIndex(getGlobalTime(props.mode));
pageIsLoaded.current = true;
}
}, [digits, pageIsLoaded, getGlobalTime, relocatePointerByIndex, props.mode]);
(0, _react.useEffect)(() => {
relocatePointerByIndex(pointer);
}, [pointer, relocatePointerByIndex]);
return /*#__PURE__*/_react.default.createElement("div", {
ref: clockFace,
className: "clock",
style: {
background: colors.surfaceVariant,
color: colors.onSurfaceVariant,
width: props.clockWidth + 'px'
}
}, /*#__PURE__*/_react.default.createElement("div", {
className: "center",
style: {
backgroundColor: colors.primary
}
}), /*#__PURE__*/_react.default.createElement("div", {
className: "digits-clockFace",
ref: digitsClockFace
}, Object.values(digits).length > 0 ? Object.values(digits).map((point, index) => /*#__PURE__*/_react.default.createElement("span", {
key: index,
id: index.toString(),
onClick: () => handleAutoRelocate(index),
style: {
transform: "translate(" + point.placement.x + "px," + point.placement.y + "px)"
}
}, props.mode === 'hours' ? index === 0 ? 12 : index : index % 5 === 0 ? index : /*#__PURE__*/_react.default.createElement("span", {
className: "no-show-minutes"
}, "."))) : ''), /*#__PURE__*/_react.default.createElement("div", {
ref: hand,
className: "hand",
style: {
background: "linear-gradient( 250deg, ".concat(colors.primary, " 50%, #AC6BFF00 0%)")
}
}), /*#__PURE__*/_react.default.createElement("div", {
ref: pointerFace,
onMouseDown: handleDrag,
className: "pointer",
style: {
backgroundColor: colors.primary,
color: colors.onPrimary
}
}));
}