UNPKG

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
"use strict"; 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 } })); }