@khanacademy/wonder-blocks-timing 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/es/index.js +167 -37
- package/dist/index.js +241 -50
- package/package.json +2 -3
- package/src/__tests__/generated-snapshot.test.js +2 -3
- package/src/components/__tests__/action-scheduler-provider.test.js +1 -0
- package/src/components/__tests__/with-action-scheduler.test.js +1 -0
- package/src/hooks/__tests__/use-interval.test.js +124 -0
- package/src/hooks/__tests__/use-scheduled-interval.test.js +453 -0
- package/src/hooks/__tests__/use-scheduled-timeout.test.js +469 -0
- package/src/hooks/__tests__/use-timeout.test.js +93 -293
- package/src/hooks/internal/use-updating-ref.js +20 -0
- package/src/hooks/use-interval.js +37 -0
- package/src/hooks/use-interval.stories.mdx +80 -0
- package/src/hooks/use-scheduled-interval.js +73 -0
- package/src/hooks/use-scheduled-interval.stories.mdx +147 -0
- package/src/hooks/use-scheduled-timeout.js +80 -0
- package/src/hooks/use-scheduled-timeout.stories.mdx +148 -0
- package/src/hooks/use-timeout.js +22 -55
- package/src/hooks/use-timeout.stories.mdx +24 -96
- package/src/index.js +3 -0
- package/LICENSE +0 -21
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @khanacademy/wonder-blocks-timing
|
|
2
|
+
|
|
3
|
+
## 2.1.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- 029b4810: Adds `useInterval()` hook that mimics the behavior of `ActionScheduler`'s
|
|
7
|
+
`interval()` method.
|
|
8
|
+
- c57cd770: Rename `useInterval` and `useTimeout` to `useScheduledInterval`
|
|
9
|
+
and `useScheduledTimeout` respectively.
|
|
10
|
+
- 29766c8e: Add `useInterval` and `useTimeout` hooks to provide a simple API for
|
|
11
|
+
using intervals and timeouts.
|
package/dist/es/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from '@babel/runtime/helpers/extends';
|
|
2
|
-
import
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
3
4
|
|
|
4
5
|
const SchedulePolicy = {
|
|
5
6
|
Immediately: "schedule-immediately",
|
|
@@ -395,7 +396,7 @@ ActionScheduler.NoopAction = {
|
|
|
395
396
|
* </ActionSchedulerProvider>
|
|
396
397
|
* ```
|
|
397
398
|
*/
|
|
398
|
-
class ActionSchedulerProvider extends Component {
|
|
399
|
+
class ActionSchedulerProvider extends React.Component {
|
|
399
400
|
constructor(...args) {
|
|
400
401
|
super(...args);
|
|
401
402
|
this._actionScheduler = new ActionScheduler();
|
|
@@ -424,59 +425,188 @@ class ActionSchedulerProvider extends Component {
|
|
|
424
425
|
* these props use the `WithActionScheduler` type.
|
|
425
426
|
*/
|
|
426
427
|
function withActionScheduler(WrappedComponent) {
|
|
427
|
-
return /*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/createElement(ActionSchedulerProvider, null, schedule => /*#__PURE__*/createElement(WrappedComponent, _extends({}, props, {
|
|
428
|
+
return /*#__PURE__*/React.forwardRef((props, ref) => /*#__PURE__*/React.createElement(ActionSchedulerProvider, null, schedule => /*#__PURE__*/React.createElement(WrappedComponent, _extends({}, props, {
|
|
428
429
|
ref: ref,
|
|
429
430
|
schedule: schedule
|
|
430
431
|
}))));
|
|
431
432
|
}
|
|
432
433
|
|
|
433
|
-
|
|
434
|
+
/**
|
|
435
|
+
* Returns a ref whose .current value is updated whenever
|
|
436
|
+
* the `value` passed to this hook changes.
|
|
437
|
+
*
|
|
438
|
+
* this is great for values that you want to reference from
|
|
439
|
+
* within a useCallback or useEffect event listener, without
|
|
440
|
+
* re-triggering the effect when the value changes
|
|
441
|
+
*
|
|
442
|
+
* @returns {{current: T}}
|
|
443
|
+
*/
|
|
444
|
+
|
|
445
|
+
const useUpdatingRef = value => {
|
|
446
|
+
const ref = useRef(value);
|
|
447
|
+
useEffect(() => {
|
|
448
|
+
ref.current = value;
|
|
449
|
+
}, [value]);
|
|
450
|
+
return ref;
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* A simple hook for using `setInterval`.
|
|
455
|
+
*
|
|
456
|
+
* @param action called every `intervalMs` when `active` is true
|
|
457
|
+
* @param intervalMs the duration between calls to `action`
|
|
458
|
+
* @param active whether or not the interval is active
|
|
459
|
+
*/
|
|
460
|
+
|
|
461
|
+
function useInterval(action, intervalMs, active) {
|
|
462
|
+
// We using a ref instead of a callback for `action` to avoid resetting
|
|
463
|
+
// the interval whenever the `action` changes.
|
|
464
|
+
const actionRef = useUpdatingRef(action);
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
if (active) {
|
|
467
|
+
const intervalId = setInterval(() => {
|
|
468
|
+
actionRef.current();
|
|
469
|
+
}, intervalMs);
|
|
470
|
+
return () => {
|
|
471
|
+
clearInterval(intervalId);
|
|
472
|
+
};
|
|
473
|
+
} // actionRef isn't actually required, but react-hooks/exhaustive-deps
|
|
474
|
+
// doesn't recognize it as a ref and thus complains if it isn't in the
|
|
475
|
+
// deps list. It isn't a big deal though since the value ofactionRef
|
|
476
|
+
// never changes (only its contents do).
|
|
477
|
+
|
|
478
|
+
}, [intervalMs, active, actionRef]);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* A simple hook for using `setTimeout`.
|
|
483
|
+
*
|
|
484
|
+
* @param action called after `timeoutMs` when `active` is true
|
|
485
|
+
* @param timeoutMs the duration after which `action` is called
|
|
486
|
+
* @param active whether or not the interval is active
|
|
487
|
+
*/
|
|
488
|
+
|
|
489
|
+
function useTimeout(action, timeoutMs, active) {
|
|
490
|
+
// We using a ref instead of a callback for `action` to avoid resetting
|
|
491
|
+
// the interval whenever the `action` changes.
|
|
492
|
+
const actionRef = useUpdatingRef(action);
|
|
493
|
+
useEffect(() => {
|
|
494
|
+
if (active) {
|
|
495
|
+
const timeoutId = setTimeout(() => {
|
|
496
|
+
actionRef.current();
|
|
497
|
+
}, timeoutMs);
|
|
498
|
+
return () => {
|
|
499
|
+
clearTimeout(timeoutId);
|
|
500
|
+
};
|
|
501
|
+
} // actionRef isn't actually required, but react-hooks/exhaustive-deps
|
|
502
|
+
// doesn't recognize it as a ref and thus complains if it isn't in the
|
|
503
|
+
// deps list. It isn't a big deal though since the value ofactionRef
|
|
504
|
+
// never changes (only its contents do).
|
|
505
|
+
|
|
506
|
+
}, [timeoutMs, active, actionRef]);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function useScheduledInterval(action, intervalMs, options) {
|
|
434
510
|
var _options$schedulePoli;
|
|
435
511
|
|
|
512
|
+
if (typeof action !== "function") {
|
|
513
|
+
throw new Error("Action must be a function");
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (intervalMs < 1) {
|
|
517
|
+
throw new Error("Interval period must be >= 1");
|
|
518
|
+
}
|
|
519
|
+
|
|
436
520
|
const schedulePolicy = (_options$schedulePoli = options == null ? void 0 : options.schedulePolicy) != null ? _options$schedulePoli : SchedulePolicy.Immediately;
|
|
437
521
|
const [isSet, setIsSet] = useState(schedulePolicy === SchedulePolicy.Immediately);
|
|
438
|
-
const
|
|
439
|
-
const
|
|
522
|
+
const set = useCallback(() => setIsSet(true), []);
|
|
523
|
+
const actionRef = useUpdatingRef(action);
|
|
524
|
+
const clear = useCallback(policy => {
|
|
525
|
+
var _policy;
|
|
526
|
+
|
|
527
|
+
policy = (_policy = policy) != null ? _policy : options == null ? void 0 : options.clearPolicy;
|
|
528
|
+
|
|
529
|
+
if (isSet && policy === ClearPolicy.Resolve) {
|
|
530
|
+
actionRef.current();
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
setIsSet(false);
|
|
534
|
+
}, // react-hooks/exhaustive-deps doesn't require refs to be
|
|
535
|
+
// listed in the deps array. Unfortunately, in this situation
|
|
536
|
+
// it doesn't recognized actionRef as a ref.
|
|
537
|
+
[actionRef, isSet, options == null ? void 0 : options.clearPolicy]);
|
|
538
|
+
const runOnUnmountRef = useUpdatingRef(isSet && (options == null ? void 0 : options.clearPolicy) === ClearPolicy.Resolve);
|
|
440
539
|
useEffect(() => {
|
|
441
|
-
mountedRef.current = true;
|
|
442
540
|
return () => {
|
|
443
|
-
|
|
444
|
-
|
|
541
|
+
// This code will only run with the component using this
|
|
542
|
+
// hook is unmounted.
|
|
543
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
544
|
+
if (runOnUnmountRef.current) {
|
|
545
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
546
|
+
actionRef.current();
|
|
547
|
+
}
|
|
548
|
+
}; // This eslint rule doesn't realize actionRef and runOnUnmountRef
|
|
549
|
+
// a both refs and thus do not have to be listed as deps.
|
|
550
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
445
551
|
}, []);
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
552
|
+
useInterval(action, intervalMs, isSet);
|
|
553
|
+
return {
|
|
554
|
+
isSet,
|
|
555
|
+
set,
|
|
556
|
+
clear
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function useScheduledTimeout(action, timeoutMs, options) {
|
|
561
|
+
var _options$schedulePoli;
|
|
453
562
|
|
|
563
|
+
if (typeof action !== "function") {
|
|
564
|
+
throw new Error("Action must be a function");
|
|
565
|
+
}
|
|
454
566
|
|
|
567
|
+
if (timeoutMs < 0) {
|
|
568
|
+
throw new Error("Timeout period must be >= 0");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const schedulePolicy = (_options$schedulePoli = options == null ? void 0 : options.schedulePolicy) != null ? _options$schedulePoli : SchedulePolicy.Immediately;
|
|
572
|
+
const [isSet, setIsSet] = useState(schedulePolicy === SchedulePolicy.Immediately);
|
|
573
|
+
const set = useCallback(() => setIsSet(true), []); // This wrapper isn't present in useScheduledInterval because we
|
|
574
|
+
// don't need to update `isSet` in that situations.
|
|
575
|
+
|
|
576
|
+
const wrappedAction = useCallback(() => {
|
|
455
577
|
setIsSet(false);
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
578
|
+
action();
|
|
579
|
+
}, [action]);
|
|
580
|
+
const actionRef = useUpdatingRef(wrappedAction);
|
|
581
|
+
const clear = useCallback(policy => {
|
|
582
|
+
var _policy;
|
|
461
583
|
|
|
584
|
+
policy = (_policy = policy) != null ? _policy : options == null ? void 0 : options.clearPolicy;
|
|
585
|
+
|
|
586
|
+
if (isSet && policy === ClearPolicy.Resolve) {
|
|
587
|
+
actionRef.current();
|
|
588
|
+
}
|
|
462
589
|
|
|
463
|
-
setIsSet(
|
|
464
|
-
},
|
|
590
|
+
setIsSet(false);
|
|
591
|
+
}, // react-hooks/exhaustive-deps doesn't require refs to be
|
|
592
|
+
// listed in the deps array. Unfortunately, in this situation
|
|
593
|
+
// it doesn't recognized actionRef as a ref.
|
|
594
|
+
[actionRef, isSet, options == null ? void 0 : options.clearPolicy]);
|
|
595
|
+
const runOnUnmountRef = useUpdatingRef(isSet && (options == null ? void 0 : options.clearPolicy) === ClearPolicy.Resolve);
|
|
465
596
|
useEffect(() => {
|
|
466
|
-
|
|
467
|
-
|
|
597
|
+
return () => {
|
|
598
|
+
// This code will only run with the component using this
|
|
599
|
+
// hook is unmounted.
|
|
600
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
601
|
+
if (runOnUnmountRef.current) {
|
|
602
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
468
603
|
actionRef.current();
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
clear();
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
}, [clear, isSet, timeoutMs]);
|
|
604
|
+
}
|
|
605
|
+
}; // This eslint rule doesn't realize actionRef and runOnUnmountRef
|
|
606
|
+
// a both refs and thus do not have to be listed as deps.
|
|
607
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
608
|
+
}, []);
|
|
609
|
+
useTimeout(wrappedAction, timeoutMs, isSet);
|
|
480
610
|
return {
|
|
481
611
|
isSet,
|
|
482
612
|
set,
|
|
@@ -484,4 +614,4 @@ function useTimeout(action, timeoutMs, options) {
|
|
|
484
614
|
};
|
|
485
615
|
}
|
|
486
616
|
|
|
487
|
-
export { ClearPolicy, SchedulePolicy, useTimeout, withActionScheduler };
|
|
617
|
+
export { ClearPolicy, SchedulePolicy, useInterval, useScheduledInterval, useScheduledTimeout, useTimeout, withActionScheduler };
|
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ module.exports =
|
|
|
82
82
|
/******/
|
|
83
83
|
/******/
|
|
84
84
|
/******/ // Load entry module and return exports
|
|
85
|
-
/******/ return __webpack_require__(__webpack_require__.s =
|
|
85
|
+
/******/ return __webpack_require__(__webpack_require__.s = 13);
|
|
86
86
|
/******/ })
|
|
87
87
|
/************************************************************************/
|
|
88
88
|
/******/ ([
|
|
@@ -111,11 +111,117 @@ module.exports = require("react");
|
|
|
111
111
|
/* 2 */
|
|
112
112
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
113
113
|
|
|
114
|
+
"use strict";
|
|
115
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useUpdatingRef; });
|
|
116
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
117
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns a ref whose .current value is updated whenever
|
|
121
|
+
* the `value` passed to this hook changes.
|
|
122
|
+
*
|
|
123
|
+
* this is great for values that you want to reference from
|
|
124
|
+
* within a useCallback or useEffect event listener, without
|
|
125
|
+
* re-triggering the effect when the value changes
|
|
126
|
+
*
|
|
127
|
+
* @returns {{current: T}}
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
const useUpdatingRef = value => {
|
|
131
|
+
const ref = Object(react__WEBPACK_IMPORTED_MODULE_0__["useRef"])(value);
|
|
132
|
+
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
|
|
133
|
+
ref.current = value;
|
|
134
|
+
}, [value]);
|
|
135
|
+
return ref;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/***/ }),
|
|
139
|
+
/* 3 */
|
|
140
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
141
|
+
|
|
142
|
+
"use strict";
|
|
143
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useInterval; });
|
|
144
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
145
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
146
|
+
/* harmony import */ var _internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A simple hook for using `setInterval`.
|
|
151
|
+
*
|
|
152
|
+
* @param action called every `intervalMs` when `active` is true
|
|
153
|
+
* @param intervalMs the duration between calls to `action`
|
|
154
|
+
* @param active whether or not the interval is active
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
function useInterval(action, intervalMs, active) {
|
|
158
|
+
// We using a ref instead of a callback for `action` to avoid resetting
|
|
159
|
+
// the interval whenever the `action` changes.
|
|
160
|
+
const actionRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_1__[/* useUpdatingRef */ "a"])(action);
|
|
161
|
+
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
|
|
162
|
+
if (active) {
|
|
163
|
+
const intervalId = setInterval(() => {
|
|
164
|
+
actionRef.current();
|
|
165
|
+
}, intervalMs);
|
|
166
|
+
return () => {
|
|
167
|
+
clearInterval(intervalId);
|
|
168
|
+
};
|
|
169
|
+
} // actionRef isn't actually required, but react-hooks/exhaustive-deps
|
|
170
|
+
// doesn't recognize it as a ref and thus complains if it isn't in the
|
|
171
|
+
// deps list. It isn't a big deal though since the value ofactionRef
|
|
172
|
+
// never changes (only its contents do).
|
|
173
|
+
|
|
174
|
+
}, [intervalMs, active, actionRef]);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/***/ }),
|
|
178
|
+
/* 4 */
|
|
179
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
180
|
+
|
|
181
|
+
"use strict";
|
|
182
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useTimeout; });
|
|
183
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
184
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
185
|
+
/* harmony import */ var _internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* A simple hook for using `setTimeout`.
|
|
190
|
+
*
|
|
191
|
+
* @param action called after `timeoutMs` when `active` is true
|
|
192
|
+
* @param timeoutMs the duration after which `action` is called
|
|
193
|
+
* @param active whether or not the interval is active
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
function useTimeout(action, timeoutMs, active) {
|
|
197
|
+
// We using a ref instead of a callback for `action` to avoid resetting
|
|
198
|
+
// the interval whenever the `action` changes.
|
|
199
|
+
const actionRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_1__[/* useUpdatingRef */ "a"])(action);
|
|
200
|
+
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
|
|
201
|
+
if (active) {
|
|
202
|
+
const timeoutId = setTimeout(() => {
|
|
203
|
+
actionRef.current();
|
|
204
|
+
}, timeoutMs);
|
|
205
|
+
return () => {
|
|
206
|
+
clearTimeout(timeoutId);
|
|
207
|
+
};
|
|
208
|
+
} // actionRef isn't actually required, but react-hooks/exhaustive-deps
|
|
209
|
+
// doesn't recognize it as a ref and thus complains if it isn't in the
|
|
210
|
+
// deps list. It isn't a big deal though since the value ofactionRef
|
|
211
|
+
// never changes (only its contents do).
|
|
212
|
+
|
|
213
|
+
}, [timeoutMs, active, actionRef]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/***/ }),
|
|
217
|
+
/* 5 */
|
|
218
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
219
|
+
|
|
114
220
|
"use strict";
|
|
115
221
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return withActionScheduler; });
|
|
116
222
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
117
223
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
118
|
-
/* harmony import */ var _action_scheduler_provider_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
224
|
+
/* harmony import */ var _action_scheduler_provider_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
|
|
119
225
|
function _extends() { _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; }; return _extends.apply(this, arguments); }
|
|
120
226
|
|
|
121
227
|
|
|
@@ -138,63 +244,136 @@ function withActionScheduler(WrappedComponent) {
|
|
|
138
244
|
}
|
|
139
245
|
|
|
140
246
|
/***/ }),
|
|
141
|
-
/*
|
|
247
|
+
/* 6 */
|
|
142
248
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
143
249
|
|
|
144
250
|
"use strict";
|
|
145
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return
|
|
251
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useScheduledInterval; });
|
|
146
252
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
147
253
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
148
254
|
/* harmony import */ var _util_policies_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
255
|
+
/* harmony import */ var _internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
|
|
256
|
+
/* harmony import */ var _use_interval_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3);
|
|
257
|
+
|
|
149
258
|
|
|
150
259
|
|
|
151
|
-
|
|
260
|
+
|
|
261
|
+
function useScheduledInterval(action, intervalMs, options) {
|
|
152
262
|
var _options$schedulePoli;
|
|
153
263
|
|
|
264
|
+
if (typeof action !== "function") {
|
|
265
|
+
throw new Error("Action must be a function");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (intervalMs < 1) {
|
|
269
|
+
throw new Error("Interval period must be >= 1");
|
|
270
|
+
}
|
|
271
|
+
|
|
154
272
|
const schedulePolicy = (_options$schedulePoli = options == null ? void 0 : options.schedulePolicy) != null ? _options$schedulePoli : _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* SchedulePolicy */ "b"].Immediately;
|
|
155
273
|
const [isSet, setIsSet] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(schedulePolicy === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* SchedulePolicy */ "b"].Immediately);
|
|
156
|
-
const
|
|
157
|
-
const
|
|
274
|
+
const set = Object(react__WEBPACK_IMPORTED_MODULE_0__["useCallback"])(() => setIsSet(true), []);
|
|
275
|
+
const actionRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__[/* useUpdatingRef */ "a"])(action);
|
|
276
|
+
const clear = Object(react__WEBPACK_IMPORTED_MODULE_0__["useCallback"])(policy => {
|
|
277
|
+
var _policy;
|
|
278
|
+
|
|
279
|
+
policy = (_policy = policy) != null ? _policy : options == null ? void 0 : options.clearPolicy;
|
|
280
|
+
|
|
281
|
+
if (isSet && policy === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* ClearPolicy */ "a"].Resolve) {
|
|
282
|
+
actionRef.current();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
setIsSet(false);
|
|
286
|
+
}, // react-hooks/exhaustive-deps doesn't require refs to be
|
|
287
|
+
// listed in the deps array. Unfortunately, in this situation
|
|
288
|
+
// it doesn't recognized actionRef as a ref.
|
|
289
|
+
[actionRef, isSet, options == null ? void 0 : options.clearPolicy]);
|
|
290
|
+
const runOnUnmountRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__[/* useUpdatingRef */ "a"])(isSet && (options == null ? void 0 : options.clearPolicy) === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* ClearPolicy */ "a"].Resolve);
|
|
158
291
|
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
|
|
159
|
-
mountedRef.current = true;
|
|
160
292
|
return () => {
|
|
161
|
-
|
|
162
|
-
|
|
293
|
+
// This code will only run with the component using this
|
|
294
|
+
// hook is unmounted.
|
|
295
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
296
|
+
if (runOnUnmountRef.current) {
|
|
297
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
298
|
+
actionRef.current();
|
|
299
|
+
}
|
|
300
|
+
}; // This eslint rule doesn't realize actionRef and runOnUnmountRef
|
|
301
|
+
// a both refs and thus do not have to be listed as deps.
|
|
302
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
163
303
|
}, []);
|
|
164
|
-
Object(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
304
|
+
Object(_use_interval_js__WEBPACK_IMPORTED_MODULE_3__[/* useInterval */ "a"])(action, intervalMs, isSet);
|
|
305
|
+
return {
|
|
306
|
+
isSet,
|
|
307
|
+
set,
|
|
308
|
+
clear
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/***/ }),
|
|
313
|
+
/* 7 */
|
|
314
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
315
|
+
|
|
316
|
+
"use strict";
|
|
317
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useScheduledTimeout; });
|
|
318
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
319
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
320
|
+
/* harmony import */ var _util_policies_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
321
|
+
/* harmony import */ var _internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
|
|
322
|
+
/* harmony import */ var _use_timeout_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
function useScheduledTimeout(action, timeoutMs, options) {
|
|
328
|
+
var _options$schedulePoli;
|
|
171
329
|
|
|
330
|
+
if (typeof action !== "function") {
|
|
331
|
+
throw new Error("Action must be a function");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (timeoutMs < 0) {
|
|
335
|
+
throw new Error("Timeout period must be >= 0");
|
|
336
|
+
}
|
|
172
337
|
|
|
338
|
+
const schedulePolicy = (_options$schedulePoli = options == null ? void 0 : options.schedulePolicy) != null ? _options$schedulePoli : _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* SchedulePolicy */ "b"].Immediately;
|
|
339
|
+
const [isSet, setIsSet] = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(schedulePolicy === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* SchedulePolicy */ "b"].Immediately);
|
|
340
|
+
const set = Object(react__WEBPACK_IMPORTED_MODULE_0__["useCallback"])(() => setIsSet(true), []); // This wrapper isn't present in useScheduledInterval because we
|
|
341
|
+
// don't need to update `isSet` in that situations.
|
|
342
|
+
|
|
343
|
+
const wrappedAction = Object(react__WEBPACK_IMPORTED_MODULE_0__["useCallback"])(() => {
|
|
173
344
|
setIsSet(false);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
345
|
+
action();
|
|
346
|
+
}, [action]);
|
|
347
|
+
const actionRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__[/* useUpdatingRef */ "a"])(wrappedAction);
|
|
348
|
+
const clear = Object(react__WEBPACK_IMPORTED_MODULE_0__["useCallback"])(policy => {
|
|
349
|
+
var _policy;
|
|
179
350
|
|
|
351
|
+
policy = (_policy = policy) != null ? _policy : options == null ? void 0 : options.clearPolicy;
|
|
180
352
|
|
|
181
|
-
|
|
182
|
-
|
|
353
|
+
if (isSet && policy === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* ClearPolicy */ "a"].Resolve) {
|
|
354
|
+
actionRef.current();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
setIsSet(false);
|
|
358
|
+
}, // react-hooks/exhaustive-deps doesn't require refs to be
|
|
359
|
+
// listed in the deps array. Unfortunately, in this situation
|
|
360
|
+
// it doesn't recognized actionRef as a ref.
|
|
361
|
+
[actionRef, isSet, options == null ? void 0 : options.clearPolicy]);
|
|
362
|
+
const runOnUnmountRef = Object(_internal_use_updating_ref_js__WEBPACK_IMPORTED_MODULE_2__[/* useUpdatingRef */ "a"])(isSet && (options == null ? void 0 : options.clearPolicy) === _util_policies_js__WEBPACK_IMPORTED_MODULE_1__[/* ClearPolicy */ "a"].Resolve);
|
|
183
363
|
Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
|
|
184
|
-
|
|
185
|
-
|
|
364
|
+
return () => {
|
|
365
|
+
// This code will only run with the component using this
|
|
366
|
+
// hook is unmounted.
|
|
367
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
368
|
+
if (runOnUnmountRef.current) {
|
|
369
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
186
370
|
actionRef.current();
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
clear();
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
}, [clear, isSet, timeoutMs]);
|
|
371
|
+
}
|
|
372
|
+
}; // This eslint rule doesn't realize actionRef and runOnUnmountRef
|
|
373
|
+
// a both refs and thus do not have to be listed as deps.
|
|
374
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
375
|
+
}, []);
|
|
376
|
+
Object(_use_timeout_js__WEBPACK_IMPORTED_MODULE_3__[/* useTimeout */ "a"])(wrappedAction, timeoutMs, isSet);
|
|
198
377
|
return {
|
|
199
378
|
isSet,
|
|
200
379
|
set,
|
|
@@ -203,14 +382,14 @@ function useTimeout(action, timeoutMs, options) {
|
|
|
203
382
|
}
|
|
204
383
|
|
|
205
384
|
/***/ }),
|
|
206
|
-
/*
|
|
385
|
+
/* 8 */
|
|
207
386
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
208
387
|
|
|
209
388
|
"use strict";
|
|
210
389
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ActionSchedulerProvider; });
|
|
211
390
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
212
391
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
213
|
-
/* harmony import */ var _util_action_scheduler_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
392
|
+
/* harmony import */ var _util_action_scheduler_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
|
|
214
393
|
|
|
215
394
|
|
|
216
395
|
|
|
@@ -244,14 +423,14 @@ class ActionSchedulerProvider extends react__WEBPACK_IMPORTED_MODULE_0__["Compon
|
|
|
244
423
|
}
|
|
245
424
|
|
|
246
425
|
/***/ }),
|
|
247
|
-
/*
|
|
426
|
+
/* 9 */
|
|
248
427
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
249
428
|
|
|
250
429
|
"use strict";
|
|
251
430
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ActionScheduler; });
|
|
252
|
-
/* harmony import */ var _timeout_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
253
|
-
/* harmony import */ var _interval_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
254
|
-
/* harmony import */ var _animation_frame_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(
|
|
431
|
+
/* harmony import */ var _timeout_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
|
|
432
|
+
/* harmony import */ var _interval_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
|
|
433
|
+
/* harmony import */ var _animation_frame_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(12);
|
|
255
434
|
|
|
256
435
|
|
|
257
436
|
|
|
@@ -332,7 +511,7 @@ ActionScheduler.NoopAction = {
|
|
|
332
511
|
};
|
|
333
512
|
|
|
334
513
|
/***/ }),
|
|
335
|
-
/*
|
|
514
|
+
/* 10 */
|
|
336
515
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
337
516
|
|
|
338
517
|
"use strict";
|
|
@@ -443,7 +622,7 @@ class Timeout {
|
|
|
443
622
|
}
|
|
444
623
|
|
|
445
624
|
/***/ }),
|
|
446
|
-
/*
|
|
625
|
+
/* 11 */
|
|
447
626
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
448
627
|
|
|
449
628
|
"use strict";
|
|
@@ -552,7 +731,7 @@ class Interval {
|
|
|
552
731
|
}
|
|
553
732
|
|
|
554
733
|
/***/ }),
|
|
555
|
-
/*
|
|
734
|
+
/* 12 */
|
|
556
735
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
557
736
|
|
|
558
737
|
"use strict";
|
|
@@ -659,7 +838,7 @@ class AnimationFrame {
|
|
|
659
838
|
}
|
|
660
839
|
|
|
661
840
|
/***/ }),
|
|
662
|
-
/*
|
|
841
|
+
/* 13 */
|
|
663
842
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
664
843
|
|
|
665
844
|
"use strict";
|
|
@@ -669,11 +848,23 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
669
848
|
|
|
670
849
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ClearPolicy", function() { return _util_policies_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
|
|
671
850
|
|
|
672
|
-
/* harmony import */ var _components_with_action_scheduler_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
851
|
+
/* harmony import */ var _components_with_action_scheduler_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
673
852
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withActionScheduler", function() { return _components_with_action_scheduler_js__WEBPACK_IMPORTED_MODULE_1__["a"]; });
|
|
674
853
|
|
|
675
|
-
/* harmony import */ var
|
|
676
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "
|
|
854
|
+
/* harmony import */ var _hooks_use_interval_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
855
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useInterval", function() { return _hooks_use_interval_js__WEBPACK_IMPORTED_MODULE_2__["a"]; });
|
|
856
|
+
|
|
857
|
+
/* harmony import */ var _hooks_use_timeout_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
|
858
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useTimeout", function() { return _hooks_use_timeout_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
|
|
859
|
+
|
|
860
|
+
/* harmony import */ var _hooks_use_scheduled_interval_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
|
|
861
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useScheduledInterval", function() { return _hooks_use_scheduled_interval_js__WEBPACK_IMPORTED_MODULE_4__["a"]; });
|
|
862
|
+
|
|
863
|
+
/* harmony import */ var _hooks_use_scheduled_timeout_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7);
|
|
864
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useScheduledTimeout", function() { return _hooks_use_scheduled_timeout_js__WEBPACK_IMPORTED_MODULE_5__["a"]; });
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
677
868
|
|
|
678
869
|
|
|
679
870
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-timing",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"design": "v1",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -20,6 +20,5 @@
|
|
|
20
20
|
"wb-dev-build-settings": "^0.2.0"
|
|
21
21
|
},
|
|
22
22
|
"author": "",
|
|
23
|
-
"license": "MIT"
|
|
24
|
-
"gitHead": "9ebea88533e702011165072f090a377e02fa3f0f"
|
|
23
|
+
"license": "MIT"
|
|
25
24
|
}
|