diff --git a/.eslintrc b/.eslintrc
index de8925d..56dedae 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -7,6 +7,7 @@
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/jsx-filename-extension": 0,
+ "import/prefer-default-export": 0,
"no-unused-expressions": [ 2,{
"allowShortCircuit": true,
}],
diff --git a/demo/components/UseTimerDemo.js b/demo/components/UseTimerDemo.js
index 543e32a..28cd1f6 100644
--- a/demo/components/UseTimerDemo.js
+++ b/demo/components/UseTimerDemo.js
@@ -13,8 +13,7 @@ export default function UseTimerDemo({ expiryTimestamp }: Object) {
pause,
resume,
restart,
- } = useTimer({ expiryTimestamp, onExpire: () => console.warn('onExpire called') });
-
+ } = useTimer({ expiryTimestamp, autoStart: true, onExpire: () => console.warn('onExpire called') });
return (
diff --git a/docs/index.js b/docs/index.js
index b4a6c41..0b4cfff 100644
--- a/docs/index.js
+++ b/docs/index.js
@@ -166,7 +166,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = UseTimerDemo;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _index = __webpack_require__(/*! ../../src/index */ \"./src/index.js\");\n\nvar _TimerStyled = __webpack_require__(/*! ./TimerStyled */ \"./demo/components/TimerStyled.js\");\n\nvar _TimerStyled2 = _interopRequireDefault(_TimerStyled);\n\nvar _Button = __webpack_require__(/*! ./Button */ \"./demo/components/Button.js\");\n\nvar _Button2 = _interopRequireDefault(_Button);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction UseTimerDemo(_ref) {\n var expiryTimestamp = _ref.expiryTimestamp;\n\n var _useTimer = (0, _index.useTimer)({ expiryTimestamp: expiryTimestamp, onExpire: function onExpire() {\n return console.warn('onExpire called');\n } }),\n seconds = _useTimer.seconds,\n minutes = _useTimer.minutes,\n hours = _useTimer.hours,\n days = _useTimer.days,\n start = _useTimer.start,\n pause = _useTimer.pause,\n resume = _useTimer.resume,\n restart = _useTimer.restart;\n\n return _react2.default.createElement(\n 'div',\n null,\n _react2.default.createElement(\n 'h2',\n null,\n 'UseTimer Demo'\n ),\n _react2.default.createElement(_TimerStyled2.default, { seconds: seconds, minutes: minutes, hours: hours, days: days }),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: start },\n 'Start'\n ),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: pause },\n 'Pause'\n ),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: resume },\n 'Resume'\n ),\n _react2.default.createElement(\n _Button2.default,\n {\n type: 'button',\n onClick: function onClick() {\n // Restarts to 10 minutes timer\n var time = new Date();\n time.setSeconds(time.getSeconds() + 600);\n restart(time);\n }\n },\n 'Restart'\n )\n );\n}\n\n//# sourceURL=webpack:///./demo/components/UseTimerDemo.js?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = UseTimerDemo;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _index = __webpack_require__(/*! ../../src/index */ \"./src/index.js\");\n\nvar _TimerStyled = __webpack_require__(/*! ./TimerStyled */ \"./demo/components/TimerStyled.js\");\n\nvar _TimerStyled2 = _interopRequireDefault(_TimerStyled);\n\nvar _Button = __webpack_require__(/*! ./Button */ \"./demo/components/Button.js\");\n\nvar _Button2 = _interopRequireDefault(_Button);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction UseTimerDemo(_ref) {\n var expiryTimestamp = _ref.expiryTimestamp;\n\n var _useTimer = (0, _index.useTimer)({ expiryTimestamp: expiryTimestamp, autoStart: false, onExpire: function onExpire() {\n return console.warn('onExpire called');\n } }),\n seconds = _useTimer.seconds,\n minutes = _useTimer.minutes,\n hours = _useTimer.hours,\n days = _useTimer.days,\n start = _useTimer.start,\n pause = _useTimer.pause,\n resume = _useTimer.resume,\n restart = _useTimer.restart;\n\n return _react2.default.createElement(\n 'div',\n null,\n _react2.default.createElement(\n 'h2',\n null,\n 'UseTimer Demo'\n ),\n _react2.default.createElement(_TimerStyled2.default, { seconds: seconds, minutes: minutes, hours: hours, days: days }),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: start },\n 'Start'\n ),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: pause },\n 'Pause'\n ),\n _react2.default.createElement(\n _Button2.default,\n { type: 'button', onClick: resume },\n 'Resume'\n ),\n _react2.default.createElement(\n _Button2.default,\n {\n type: 'button',\n onClick: function onClick() {\n // Restarts to 10 minutes timer\n var time = new Date();\n time.setSeconds(time.getSeconds() + 600);\n restart(time);\n }\n },\n 'Restart'\n )\n );\n}\n\n//# sourceURL=webpack:///./demo/components/UseTimerDemo.js?");
/***/ }),
@@ -443,6 +443,30 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th
/***/ }),
+/***/ "./src/hooks/index.js":
+/*!****************************!*\
+ !*** ./src/hooks/index.js ***!
+ \****************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.useInterval = undefined;\n\nvar _useInterval = __webpack_require__(/*! ./useInterval */ \"./src/hooks/useInterval.js\");\n\nvar _useInterval2 = _interopRequireDefault(_useInterval);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.useInterval = _useInterval2.default;\n\n//# sourceURL=webpack:///./src/hooks/index.js?");
+
+/***/ }),
+
+/***/ "./src/hooks/useInterval.js":
+/*!**********************************!*\
+ !*** ./src/hooks/useInterval.js ***!
+ \**********************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = useInterval;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nfunction useInterval(callback, delay) {\n var callbacRef = (0, _react.useRef)();\n\n // update callback function with current render callback that has access to latest props and state\n (0, _react.useEffect)(function () {\n callbacRef.current = callback;\n });\n\n (0, _react.useEffect)(function () {\n if (!delay) {\n return function () {};\n }\n\n var interval = setInterval(function () {\n callbacRef.current && callbacRef.current();\n }, delay);\n return function () {\n return clearInterval(interval);\n };\n }, [delay]);\n}\n\n//# sourceURL=webpack:///./src/hooks/useInterval.js?");
+
+/***/ }),
+
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
@@ -463,7 +487,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useStopwatch;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nfunction useStopwatch(settings) {\n var _ref = settings || {},\n autoStart = _ref.autoStart,\n offsetTimestamp = _ref.offsetTimestamp;\n\n var _useState = (0, _react.useState)(_utils.Time.getSecondsFromExpiry(offsetTimestamp || 0)),\n _useState2 = _slicedToArray(_useState, 2),\n seconds = _useState2[0],\n setSeconds = _useState2[1];\n\n var _useState3 = (0, _react.useState)(autoStart),\n _useState4 = _slicedToArray(_useState3, 2),\n isRunning = _useState4[0],\n setIsRunning = _useState4[1];\n\n var intervalRef = (0, _react.useRef)();\n\n function clearIntervalRef() {\n if (intervalRef.current) {\n setIsRunning(false);\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n }\n\n function start() {\n if (!intervalRef.current) {\n setIsRunning(true);\n intervalRef.current = setInterval(function () {\n return setSeconds(function (prevSeconds) {\n return prevSeconds + 1;\n });\n }, 1000);\n }\n }\n\n function pause() {\n clearIntervalRef();\n }\n\n function reset(offset) {\n clearIntervalRef();\n setSeconds(_utils.Time.getSecondsFromExpiry(offset || 0));\n if (autoStart) {\n start();\n }\n }\n\n // didMount effect\n (0, _react.useEffect)(function () {\n if (autoStart) {\n start();\n }\n return clearIntervalRef;\n }, []);\n\n return _extends({}, _utils.Time.getTimeFromSeconds(seconds), { start: start, pause: pause, reset: reset, isRunning: isRunning\n });\n}\n\n//# sourceURL=webpack:///./src/useStopwatch.js?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useStopwatch;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nvar _hooks = __webpack_require__(/*! ./hooks */ \"./src/hooks/index.js\");\n\nfunction useStopwatch(_ref) {\n var autoStart = _ref.autoStart,\n offsetTimestamp = _ref.offsetTimestamp;\n\n var _useState = (0, _react.useState)(_utils.Time.getSecondsFromExpiry(offsetTimestamp || 0)),\n _useState2 = _slicedToArray(_useState, 2),\n seconds = _useState2[0],\n setSeconds = _useState2[1];\n\n var _useState3 = (0, _react.useState)(autoStart),\n _useState4 = _slicedToArray(_useState3, 2),\n isRunning = _useState4[0],\n setIsRunning = _useState4[1];\n\n (0, _hooks.useInterval)(function () {\n setSeconds(function (prevSeconds) {\n return prevSeconds + 1;\n });\n }, isRunning ? 1000 : null);\n\n function start() {\n setIsRunning(true);\n }\n\n function pause() {\n setIsRunning(false);\n }\n\n function reset(offset) {\n setIsRunning(autoStart);\n setSeconds(_utils.Time.getSecondsFromExpiry(offset || 0));\n }\n\n return _extends({}, _utils.Time.getTimeFromSeconds(seconds), { start: start, pause: pause, reset: reset, isRunning: isRunning\n });\n}\n\n//# sourceURL=webpack:///./src/useStopwatch.js?");
/***/ }),
@@ -475,7 +499,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useTime;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nfunction useTime(settings) {\n var _ref = settings || {},\n format = _ref.format;\n\n var _useState = (0, _react.useState)(_utils.Time.getSecondsFromTimeNow()),\n _useState2 = _slicedToArray(_useState, 2),\n seconds = _useState2[0],\n setSeconds = _useState2[1];\n\n var intervalRef = (0, _react.useRef)();\n\n function clearIntervalRef() {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n }\n\n function start() {\n if (!intervalRef.current) {\n intervalRef.current = setInterval(function () {\n return setSeconds(_utils.Time.getSecondsFromTimeNow());\n }, 1000);\n }\n }\n\n // didMount effect\n (0, _react.useEffect)(function () {\n start();\n return clearIntervalRef;\n }, []);\n\n return _extends({}, _utils.Time.getFormattedTimeFromSeconds(seconds, format));\n}\n\n//# sourceURL=webpack:///./src/useTime.js?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useTime;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nvar _hooks = __webpack_require__(/*! ./hooks */ \"./src/hooks/index.js\");\n\nfunction useTime(_ref) {\n var format = _ref.format;\n\n var _useState = (0, _react.useState)(_utils.Time.getSecondsFromTimeNow()),\n _useState2 = _slicedToArray(_useState, 2),\n seconds = _useState2[0],\n setSeconds = _useState2[1];\n\n (0, _hooks.useInterval)(function () {\n setSeconds(_utils.Time.getSecondsFromTimeNow());\n }, 1000);\n\n return _extends({}, _utils.Time.getFormattedTimeFromSeconds(seconds, format));\n}\n\n//# sourceURL=webpack:///./src/useTime.js?");
/***/ }),
@@ -487,7 +511,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useTimer;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nfunction useTimer(settings) {\n var _ref = settings || {},\n expiry = _ref.expiryTimestamp,\n onExpire = _ref.onExpire;\n\n var _useState = (0, _react.useState)(expiry),\n _useState2 = _slicedToArray(_useState, 2),\n expiryTimestamp = _useState2[0],\n setExpiryTimestamp = _useState2[1];\n\n var _useState3 = (0, _react.useState)(_utils.Time.getSecondsFromExpiry(expiryTimestamp)),\n _useState4 = _slicedToArray(_useState3, 2),\n seconds = _useState4[0],\n setSeconds = _useState4[1];\n\n var _useState5 = (0, _react.useState)(true),\n _useState6 = _slicedToArray(_useState5, 2),\n isRunning = _useState6[0],\n setIsRunning = _useState6[1];\n\n var intervalRef = (0, _react.useRef)();\n\n function clearIntervalRef() {\n if (intervalRef.current) {\n setIsRunning(false);\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n }\n\n function handleExpire() {\n clearIntervalRef();\n _utils.Validate.onExpire(onExpire) && onExpire();\n }\n\n function start() {\n if (!intervalRef.current) {\n setIsRunning(true);\n intervalRef.current = setInterval(function () {\n var secondsValue = _utils.Time.getSecondsFromExpiry(expiryTimestamp);\n if (secondsValue <= 0) {\n handleExpire();\n }\n setSeconds(secondsValue);\n }, 1000);\n }\n }\n\n function pause() {\n clearIntervalRef();\n }\n\n function resume() {\n if (!intervalRef.current) {\n setIsRunning(true);\n intervalRef.current = setInterval(function () {\n return setSeconds(function (prevSeconds) {\n var secondsValue = prevSeconds - 1;\n if (secondsValue <= 0) {\n handleExpire();\n }\n return secondsValue;\n });\n }, 1000);\n }\n }\n\n function restart(newExpiryTimestamp) {\n clearIntervalRef();\n setExpiryTimestamp(newExpiryTimestamp);\n }\n\n function handleExtraMilliSeconds(secondsValue, extraMilliSeconds) {\n setIsRunning(true);\n intervalRef.current = setTimeout(function () {\n var currentSeconds = _utils.Time.getSecondsFromExpiry(expiryTimestamp);\n setSeconds(currentSeconds);\n if (currentSeconds <= 0) {\n handleExpire();\n } else {\n intervalRef.current = undefined;\n start();\n }\n }, extraMilliSeconds);\n }\n\n (0, _react.useEffect)(function () {\n if (_utils.Validate.expiryTimestamp(expiryTimestamp)) {\n var secondsValue = _utils.Time.getSecondsFromExpiry(expiryTimestamp);\n var extraMilliSeconds = Math.floor((secondsValue - Math.floor(secondsValue)) * 1000);\n setSeconds(secondsValue);\n if (extraMilliSeconds > 0) {\n handleExtraMilliSeconds(secondsValue, extraMilliSeconds);\n } else {\n start();\n }\n }\n return clearIntervalRef;\n }, [expiryTimestamp]);\n\n return _extends({}, _utils.Time.getTimeFromSeconds(seconds), { start: start, pause: pause, resume: resume, restart: restart, isRunning: isRunning\n });\n}\n\n//# sourceURL=webpack:///./src/useTimer.js?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nexports.default = useTimer;\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _utils = __webpack_require__(/*! ./utils */ \"./src/utils/index.js\");\n\nvar _hooks = __webpack_require__(/*! ./hooks */ \"./src/hooks/index.js\");\n\nfunction useTimer(_ref) {\n var expiry = _ref.expiryTimestamp,\n onExpire = _ref.onExpire,\n autoStart = _ref.autoStart;\n\n var _useState = (0, _react.useState)(expiry),\n _useState2 = _slicedToArray(_useState, 2),\n expiryTimestamp = _useState2[0],\n setExpiryTimestamp = _useState2[1];\n\n var _useState3 = (0, _react.useState)(_utils.Time.getSecondsFromExpiry(expiryTimestamp)),\n _useState4 = _slicedToArray(_useState3, 2),\n seconds = _useState4[0],\n setSeconds = _useState4[1];\n\n var _useState5 = (0, _react.useState)(autoStart),\n _useState6 = _slicedToArray(_useState5, 2),\n isRunning = _useState6[0],\n setIsRunning = _useState6[1];\n\n var _useState7 = (0, _react.useState)(autoStart),\n _useState8 = _slicedToArray(_useState7, 2),\n didStart = _useState8[0],\n setDidStart = _useState8[1];\n\n function handleExpire() {\n _utils.Validate.onExpire(onExpire) && onExpire();\n }\n\n function pause() {\n setIsRunning(false);\n }\n\n function resume() {\n var time = new Date();\n time.setSeconds(time.getSeconds() + seconds); // calculate new expiry timestamp based on last paused seconds count\n setExpiryTimestamp(time);\n setIsRunning(true);\n setSeconds(_utils.Time.getSecondsFromExpiry(time));\n }\n\n function start() {\n if (didStart) {\n setIsRunning(true);\n setSeconds(_utils.Time.getSecondsFromExpiry(expiryTimestamp));\n } else {\n resume();\n setDidStart(true);\n }\n }\n\n function restart(newExpiryTimestamp) {\n setDidStart(autoStart);\n setIsRunning(autoStart);\n setExpiryTimestamp(newExpiryTimestamp);\n setSeconds(_utils.Time.getSecondsFromExpiry(newExpiryTimestamp));\n }\n\n (0, _hooks.useInterval)(function () {\n var secondsValue = _utils.Time.getSecondsFromExpiry(expiryTimestamp);\n if (secondsValue <= 0) {\n handleExpire();\n }\n setSeconds(secondsValue);\n }, isRunning ? 1000 : null);\n\n return _extends({}, _utils.Time.getTimeFromSeconds(seconds), { start: start, pause: pause, resume: resume, restart: restart, isRunning: isRunning\n });\n}\n\n//# sourceURL=webpack:///./src/useTimer.js?");
/***/ }),
diff --git a/readme.md b/readme.md
index f747d2a..ef8b809 100644
--- a/readme.md
+++ b/readme.md
@@ -33,7 +33,7 @@ function MyTimer({ expiryTimestamp }) {
pause,
resume,
restart,
- } = useTimer({ expiryTimestamp, onExpire: () => console.warn('onExpire called') });
+ } = useTimer({ expiryTimestamp, autoStart: true, onExpire: () => console.warn('onExpire called') });
return (
@@ -73,8 +73,10 @@ export default function App() {
| key | Type | Required | Description |
| --- | --- | --- | ---- |
| expiryTimestamp | number(timestamp) | YES | this will define for how long the timer will be running |
+| autoStart | boolean | No | flag to decide if timer should start automatically |
| onExpire | Function | No | callback function to be executed once countdown timer is expired |
+
### Values
| key | Type | Description |
diff --git a/src/hooks/index.js b/src/hooks/index.js
new file mode 100644
index 0000000..28e8735
--- /dev/null
+++ b/src/hooks/index.js
@@ -0,0 +1,5 @@
+import useInterval from './useInterval';
+
+export {
+ useInterval,
+};
diff --git a/src/hooks/useInterval.js b/src/hooks/useInterval.js
new file mode 100644
index 0000000..7f4603f
--- /dev/null
+++ b/src/hooks/useInterval.js
@@ -0,0 +1,21 @@
+import { useEffect, useRef } from 'react';
+
+export default function useInterval(callback, delay) {
+ const callbacRef = useRef();
+
+ // update callback function with current render callback that has access to latest props and state
+ useEffect(() => {
+ callbacRef.current = callback;
+ });
+
+ useEffect(() => {
+ if (!delay) {
+ return () => {};
+ }
+
+ const interval = setInterval(() => {
+ callbacRef.current && callbacRef.current();
+ }, delay);
+ return () => clearInterval(interval);
+ }, [delay]);
+}
diff --git a/src/useStopwatch.js b/src/useStopwatch.js
index a92233c..d5ab05f 100644
--- a/src/useStopwatch.js
+++ b/src/useStopwatch.js
@@ -1,48 +1,28 @@
-import { useState, useEffect, useRef } from 'react';
+import { useState } from 'react';
import { Time } from './utils';
+import { useInterval } from './hooks';
-export default function useStopwatch(settings) {
- const { autoStart, offsetTimestamp } = settings || {};
-
+export default function useStopwatch({ autoStart, offsetTimestamp }) {
const [seconds, setSeconds] = useState(Time.getSecondsFromExpiry(offsetTimestamp || 0));
const [isRunning, setIsRunning] = useState(autoStart);
- const intervalRef = useRef();
- function clearIntervalRef() {
- if (intervalRef.current) {
- setIsRunning(false);
- clearInterval(intervalRef.current);
- intervalRef.current = undefined;
- }
- }
+ useInterval(() => {
+ setSeconds((prevSeconds) => (prevSeconds + 1));
+ }, isRunning ? 1000 : null);
function start() {
- if (!intervalRef.current) {
- setIsRunning(true);
- intervalRef.current = setInterval(() => setSeconds((prevSeconds) => (prevSeconds + 1)), 1000);
- }
+ setIsRunning(true);
}
function pause() {
- clearIntervalRef();
+ setIsRunning(false);
}
function reset(offset: number) {
- clearIntervalRef();
+ setIsRunning(autoStart);
setSeconds(Time.getSecondsFromExpiry(offset || 0));
- if (autoStart) {
- start();
- }
}
- // didMount effect
- useEffect(() => {
- if (autoStart) {
- start();
- }
- return clearIntervalRef;
- }, []);
-
return {
...Time.getTimeFromSeconds(seconds), start, pause, reset, isRunning,
};
diff --git a/src/useTime.js b/src/useTime.js
index ebd47de..106347b 100644
--- a/src/useTime.js
+++ b/src/useTime.js
@@ -1,31 +1,13 @@
-import { useState, useEffect, useRef } from 'react';
+import { useState } from 'react';
import { Time } from './utils';
+import { useInterval } from './hooks';
-export default function useTime(settings) {
- const { format } = settings || {};
-
+export default function useTime({ format }) {
const [seconds, setSeconds] = useState(Time.getSecondsFromTimeNow());
- const intervalRef = useRef();
-
- function clearIntervalRef() {
- if (intervalRef.current) {
- clearInterval(intervalRef.current);
- intervalRef.current = undefined;
- }
- }
-
- function start() {
- if (!intervalRef.current) {
- intervalRef.current = setInterval(() => setSeconds(Time.getSecondsFromTimeNow()), 1000);
- }
- }
-
- // didMount effect
- useEffect(() => {
- start();
- return clearIntervalRef;
- }, []);
+ useInterval(() => {
+ setSeconds(Time.getSecondsFromTimeNow());
+ }, 1000);
return {
...Time.getFormattedTimeFromSeconds(seconds, format),
diff --git a/src/useTimer.js b/src/useTimer.js
index aa6e084..41d21bc 100644
--- a/src/useTimer.js
+++ b/src/useTimer.js
@@ -1,89 +1,61 @@
-import { useState, useEffect, useRef } from 'react';
+import { useState } from 'react';
import { Time, Validate } from './utils';
+import { useInterval } from './hooks';
-export default function useTimer(settings) {
- const { expiryTimestamp: expiry, onExpire } = settings || {};
+const DEFAULT_DELAY = 1000;
+export default function useTimer({ expiryTimestamp: expiry, onExpire, autoStart }) {
const [expiryTimestamp, setExpiryTimestamp] = useState(expiry);
const [seconds, setSeconds] = useState(Time.getSecondsFromExpiry(expiryTimestamp));
- const [isRunning, setIsRunning] = useState(true);
- const intervalRef = useRef();
-
- function clearIntervalRef() {
- if (intervalRef.current) {
- setIsRunning(false);
- clearInterval(intervalRef.current);
- intervalRef.current = undefined;
- }
- }
+ const [isRunning, setIsRunning] = useState(autoStart);
+ const [didStart, setDidStart] = useState(autoStart);
+ const extraMilliSeconds = Math.floor((seconds - Math.floor(seconds)) * 1000);
+ const [delay, setDelay] = useState(extraMilliSeconds > 0 ? extraMilliSeconds : 1000);
function handleExpire() {
- clearIntervalRef();
Validate.onExpire(onExpire) && onExpire();
- }
-
- function start() {
- if (!intervalRef.current) {
- setIsRunning(true);
- intervalRef.current = setInterval(() => {
- const secondsValue = Time.getSecondsFromExpiry(expiryTimestamp);
- if (secondsValue <= 0) {
- handleExpire();
- }
- setSeconds(secondsValue);
- }, 1000);
- }
+ setIsRunning(false);
+ setDelay(null);
}
function pause() {
- clearIntervalRef();
+ setIsRunning(false);
}
- function resume() {
- if (!intervalRef.current) {
- setIsRunning(true);
- intervalRef.current = setInterval(() => setSeconds((prevSeconds) => {
- const secondsValue = prevSeconds - 1;
- if (secondsValue <= 0) {
- handleExpire();
- }
- return secondsValue;
- }), 1000);
- }
- }
-
- function restart(newExpiryTimestamp) {
- clearIntervalRef();
+ function restart(newExpiryTimestamp, newAutoStart) {
+ const secondsValue = Time.getSecondsFromExpiry(newExpiryTimestamp);
+ const extraMilliSecondsValue = Math.floor((secondsValue - Math.floor(secondsValue)) * 1000);
+ setDelay(extraMilliSecondsValue > 0 ? extraMilliSecondsValue : 1000);
+ setDidStart(newAutoStart);
+ setIsRunning(newAutoStart);
setExpiryTimestamp(newExpiryTimestamp);
+ setSeconds(secondsValue);
}
- function handleExtraMilliSeconds(secondsValue, extraMilliSeconds) {
- setIsRunning(true);
- intervalRef.current = setTimeout(() => {
- const currentSeconds = Time.getSecondsFromExpiry(expiryTimestamp);
- setSeconds(currentSeconds);
- if (currentSeconds <= 0) {
- handleExpire();
- } else {
- intervalRef.current = undefined;
- start();
- }
- }, extraMilliSeconds);
+ function resume() {
+ const time = new Date();
+ time.setMilliseconds(time.getMilliseconds() + (seconds * 1000));
+ restart(time, true);
}
- useEffect(() => {
- if (Validate.expiryTimestamp(expiryTimestamp)) {
- const secondsValue = Time.getSecondsFromExpiry(expiryTimestamp);
- const extraMilliSeconds = Math.floor((secondsValue - Math.floor(secondsValue)) * 1000);
- setSeconds(secondsValue);
- if (extraMilliSeconds > 0) {
- handleExtraMilliSeconds(secondsValue, extraMilliSeconds);
- } else {
- start();
- }
+ function start() {
+ if (didStart) {
+ setSeconds(Time.getSecondsFromExpiry(expiryTimestamp));
+ setIsRunning(true);
+ } else {
+ resume();
}
- return clearIntervalRef;
- }, [expiryTimestamp]);
+ }
+ useInterval(() => {
+ if (delay !== DEFAULT_DELAY) {
+ setDelay(DEFAULT_DELAY);
+ }
+ const secondsValue = Time.getSecondsFromExpiry(expiryTimestamp);
+ setSeconds(secondsValue);
+ if (secondsValue <= 0) {
+ handleExpire();
+ }
+ }, isRunning ? delay : null);
return {
...Time.getTimeFromSeconds(seconds), start, pause, resume, restart, isRunning,