@khanacademy/wonder-blocks-timing 4.0.1 → 5.0.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/with-action-scheduler.d.ts +4 -1
  3. package/dist/es/index.js +93 -105
  4. package/dist/hooks/use-interval.d.ts +27 -5
  5. package/dist/hooks/use-timeout.d.ts +27 -5
  6. package/dist/index.d.ts +2 -5
  7. package/dist/index.js +92 -105
  8. package/dist/util/animation-frame.d.ts +6 -6
  9. package/dist/util/interval.d.ts +8 -8
  10. package/dist/util/policies.d.ts +12 -8
  11. package/dist/util/timeout.d.ts +8 -7
  12. package/dist/util/types.d.ts +18 -10
  13. package/package.json +3 -3
  14. package/src/components/with-action-scheduler.tsx +9 -1
  15. package/src/hooks/__tests__/use-interval.test.ts +453 -56
  16. package/src/hooks/__tests__/use-timeout.test.ts +412 -58
  17. package/src/hooks/use-interval.ts +90 -25
  18. package/src/hooks/use-timeout.ts +90 -25
  19. package/src/index.ts +4 -14
  20. package/src/util/__tests__/animation-frame.test.ts +9 -10
  21. package/src/util/animation-frame.ts +12 -16
  22. package/src/util/interval.ts +13 -18
  23. package/src/util/policies.ts +13 -8
  24. package/src/util/timeout.ts +14 -18
  25. package/src/util/types.ts +19 -11
  26. package/tsconfig-build.json +2 -4
  27. package/tsconfig-build.tsbuildinfo +1 -1
  28. package/dist/components/action-scheduler-provider.js.flow +0 -33
  29. package/dist/components/with-action-scheduler.js.flow +0 -22
  30. package/dist/hooks/internal/use-updating-ref.d.ts +0 -13
  31. package/dist/hooks/internal/use-updating-ref.js.flow +0 -20
  32. package/dist/hooks/use-interval.js.flow +0 -17
  33. package/dist/hooks/use-scheduled-interval.d.ts +0 -2
  34. package/dist/hooks/use-scheduled-interval.js.flow +0 -12
  35. package/dist/hooks/use-scheduled-timeout.d.ts +0 -2
  36. package/dist/hooks/use-scheduled-timeout.js.flow +0 -12
  37. package/dist/hooks/use-timeout.js.flow +0 -17
  38. package/dist/index.js.flow +0 -31
  39. package/dist/util/action-scheduler.js.flow +0 -38
  40. package/dist/util/animation-frame.js.flow +0 -70
  41. package/dist/util/interval.js.flow +0 -69
  42. package/dist/util/policies.js.flow +0 -14
  43. package/dist/util/timeout.js.flow +0 -71
  44. package/dist/util/types.js.flow +0 -232
  45. package/dist/util/types.typestest.js.flow +0 -6
  46. package/src/hooks/__tests__/use-scheduled-interval.test.ts +0 -460
  47. package/src/hooks/__tests__/use-scheduled-timeout.test.ts +0 -478
  48. package/src/hooks/internal/use-updating-ref.ts +0 -23
  49. package/src/hooks/use-scheduled-interval.ts +0 -72
  50. package/src/hooks/use-scheduled-timeout.ts +0 -79
@@ -1,36 +1,101 @@
1
- import {useEffect} from "react";
1
+ import {useEffect, useMemo, useRef} from "react";
2
+ import {ClearPolicy, ActionPolicy} from "../util/policies";
2
3
 
3
- import {useUpdatingRef} from "./internal/use-updating-ref";
4
+ import type {ITimeout, HookOptions} from "../util/types";
5
+
6
+ import Timeout from "../util/timeout";
4
7
 
5
8
  /**
6
- * A simple hook for using `setTimeout`.
9
+ * Hook providing access to a scheduled timeout.
7
10
  *
8
- * @param action called after `timeoutMs` when `active` is true
9
- * @param timeoutMs the duration after which `action` is called
10
- * @param active whether or not the interval is active
11
+ * @param action The action to be invoked when the timeout period has
12
+ * passed. By default, this will not cause the timeout to restart if it changes.
13
+ * This makes it easier to use with inline lambda functions rather than
14
+ * requiring consumers to wrap their action in a `useCallback`. To change
15
+ * this behavior, see the `actionPolicy` option.
16
+ * @param timeoutMs The timeout period. If this changes, the timeout will
17
+ * be reset per the `schedulePolicy` option.
18
+ * @param options Options for the hook.
19
+ * @param options.actionPolicy Determines how the action is handled when it
20
+ * changes. By default, the action is replaced but the timeout is not reset,
21
+ * and the updated action will be invoked when the timeout next fires.
22
+ * If you want to reset the timeout when the action changes, use
23
+ * `ActionPolicy.Reset`.
24
+ * @param options.clearPolicy Determines how the timeout is cleared when the
25
+ * component is unmounted or the timeout is recreated. By default, the
26
+ * timeout is cleared immediately. If you want to let the timeout run to
27
+ * completion, use `ClearPolicy.Resolve`. This is NOT applied if the timeout
28
+ * is cleared manually via the `clear()` method on the returned API.
29
+ * @param options.schedulePolicy Determines when the timeout is scheduled.
30
+ * By default, the timeout is scheduled immediately. If you want to delay
31
+ * scheduling the timeout, use `SchedulePolicy.OnDemand`.
32
+ * @returns An `ITimeout` API for interacting with the given timeout. This
33
+ * API is a no-op if called when not mounted. This means that any calls prior
34
+ * to mounting or after unmounting will not have any effect.
11
35
  */
12
36
  export function useTimeout(
13
37
  action: () => unknown,
14
38
  timeoutMs: number,
15
- active: boolean,
16
- ) {
17
- // We using a ref instead of a callback for `action` to avoid resetting
18
- // the interval whenever the `action` changes.
19
- const actionRef = useUpdatingRef(action);
39
+ options: HookOptions = {},
40
+ ): ITimeout {
41
+ const {actionPolicy, clearPolicy, schedulePolicy} = options;
42
+ const actionProxyRef = useRef<() => unknown>(action);
43
+ const timeoutRef = useRef<ITimeout | null>(null);
20
44
 
21
- useEffect(() => {
22
- if (active) {
23
- const timeoutId = setTimeout(() => {
24
- actionRef.current();
25
- }, timeoutMs);
26
-
27
- return () => {
28
- clearTimeout(timeoutId);
29
- };
45
+ // Since we are passing our proxy function to the timeout instance,
46
+ // it's check that the action is a function will never fail. So, we have to
47
+ // do that check ourselves, and we do it here.
48
+ if (typeof action !== "function") {
49
+ throw new Error("Action must be a function");
50
+ }
51
+
52
+ // If we're rendered with an updated action, we want to update the ref
53
+ // so the existing timeout gets the new action, and then reset the
54
+ // timeout if our action policy calls for it.
55
+ if (action !== actionProxyRef.current) {
56
+ actionProxyRef.current = action;
57
+ if (actionPolicy === ActionPolicy.Reset) {
58
+ timeoutRef.current?.set();
30
59
  }
31
- // actionRef isn't actually required, but react-hooks/exhaustive-deps
32
- // doesn't recognize it as a ref and thus complains if it isn't in the
33
- // deps list. It isn't a big deal though since the value ofactionRef
34
- // never changes (only its contents do).
35
- }, [timeoutMs, active, actionRef]);
60
+ }
61
+
62
+ // This effect updates the timeout when the timeoutMs, clearPolicy,
63
+ // or schedulePolicy changes.
64
+ useEffect(() => {
65
+ // Make a new timeout.
66
+ timeoutRef.current = new Timeout(
67
+ () => {
68
+ actionProxyRef.current?.();
69
+ },
70
+ timeoutMs,
71
+ schedulePolicy,
72
+ );
73
+
74
+ // Clear the interval when the effect is cleaned up, if necessary,
75
+ // making sure to use the clear policy.
76
+ return () => {
77
+ timeoutRef.current?.clear(clearPolicy);
78
+ timeoutRef.current = null;
79
+ };
80
+ }, [timeoutMs, clearPolicy, schedulePolicy]);
81
+
82
+ // This is the API we expose to the consumer. We expose this rather than
83
+ // the interval instance itself so that the API we give back is stable
84
+ // even if the underlying interval instance changes.
85
+ const externalApi = useMemo(
86
+ () => ({
87
+ set: () => {
88
+ timeoutRef.current?.set();
89
+ },
90
+ clear: (policy?: ClearPolicy) => {
91
+ timeoutRef.current?.clear(policy);
92
+ },
93
+ get isSet() {
94
+ return timeoutRef.current?.isSet ?? false;
95
+ },
96
+ }),
97
+ [],
98
+ );
99
+
100
+ return externalApi;
36
101
  }
package/src/index.ts CHANGED
@@ -1,13 +1,3 @@
1
- import type {
2
- IAnimationFrame,
3
- IInterval,
4
- IScheduleActions,
5
- ITimeout,
6
- WithActionScheduler,
7
- WithActionSchedulerProps,
8
- WithoutActionScheduler,
9
- } from "./util/types";
10
-
11
1
  export type {
12
2
  IAnimationFrame,
13
3
  IInterval,
@@ -16,12 +6,12 @@ export type {
16
6
  WithActionScheduler,
17
7
  WithActionSchedulerProps,
18
8
  WithoutActionScheduler,
19
- };
9
+ HookOptions,
10
+ Options,
11
+ } from "./util/types";
20
12
 
21
- export {SchedulePolicy, ClearPolicy} from "./util/policies";
13
+ export {SchedulePolicy, ClearPolicy, ActionPolicy} from "./util/policies";
22
14
  export {default as ActionSchedulerProvider} from "./components/action-scheduler-provider";
23
15
  export {default as withActionScheduler} from "./components/with-action-scheduler";
24
16
  export {useInterval} from "./hooks/use-interval";
25
17
  export {useTimeout} from "./hooks/use-timeout";
26
- export {useScheduledInterval} from "./hooks/use-scheduled-interval";
27
- export {useScheduledTimeout} from "./hooks/use-scheduled-timeout";
@@ -9,8 +9,7 @@ describe("AnimationFrame", () => {
9
9
  // it here and map it to timeouts, that way we can use the fake timer
10
10
  // API to test our animation frame things.
11
11
  jest.spyOn(global, "requestAnimationFrame").mockImplementation(
12
- // @ts-expect-error [FEI-5019] - TS2345 - Argument of type '(fn: any, ...args: any) => NodeJS.Timeout' is not assignable to parameter of type '(callback: FrameRequestCallback) => number'.
13
- (fn: any, ...args: any) => setTimeout(fn, 0),
12
+ (fn: any, ...args: any) => setTimeout(fn, 0) as any,
14
13
  );
15
14
  jest.spyOn(global, "cancelAnimationFrame").mockImplementation(
16
15
  (id: any, ...args: any) => clearTimeout(id),
@@ -46,13 +45,14 @@ describe("AnimationFrame", () => {
46
45
 
47
46
  it("requests an animation frame when schedule policy is SchedulePolicy.Immediately", () => {
48
47
  // Arrange
48
+ const spy = jest.spyOn(global, "requestAnimationFrame");
49
49
 
50
50
  // Act
51
51
  // eslint-disable-next-line no-new
52
52
  new AnimationFrame(() => {}, SchedulePolicy.Immediately);
53
53
 
54
54
  // Assert
55
- expect(requestAnimationFrame).toHaveBeenCalledTimes(1);
55
+ expect(spy).toHaveBeenCalledTimes(1);
56
56
  });
57
57
  });
58
58
 
@@ -98,27 +98,25 @@ describe("AnimationFrame", () => {
98
98
  describe("#set", () => {
99
99
  it("should call requestAnimationFrame", () => {
100
100
  // Arrange
101
+ const spy = jest.spyOn(global, "requestAnimationFrame");
101
102
  const animationFrame = new AnimationFrame(() => {});
102
103
 
103
104
  // Act
104
105
  animationFrame.set();
105
106
 
106
107
  // Assert
107
- expect(requestAnimationFrame).toHaveBeenNthCalledWith(
108
- 1,
109
- expect.any(Function),
110
- );
108
+ expect(spy).toHaveBeenNthCalledWith(1, expect.any(Function));
111
109
  });
112
110
 
113
111
  it("should invoke requestAnimationFrame to call the given action", () => {
114
112
  // Arrange
113
+ const spy = jest.spyOn(global, "requestAnimationFrame");
115
114
  const action = jest.fn();
116
115
  const animationFrame = new AnimationFrame((time: any) =>
117
116
  action(time),
118
117
  );
119
118
  animationFrame.set();
120
- // @ts-expect-error [FEI-5019] - TS2339 - Property 'mock' does not exist on type '(callback: FrameRequestCallback) => number'.
121
- const scheduledAction = requestAnimationFrame.mock.calls[0][0];
119
+ const scheduledAction = spy.mock.calls[0][0];
122
120
 
123
121
  // Act
124
122
  scheduledAction(2001);
@@ -144,6 +142,7 @@ describe("AnimationFrame", () => {
144
142
 
145
143
  it("should set the timeout again if it has already executed", () => {
146
144
  // Arrange
145
+ const spy = jest.spyOn(global, "requestAnimationFrame");
147
146
  const action = jest.fn();
148
147
  const animationFrame = new AnimationFrame(
149
148
  action,
@@ -156,7 +155,7 @@ describe("AnimationFrame", () => {
156
155
  animationFrame.set();
157
156
 
158
157
  // Assert
159
- expect(requestAnimationFrame).toHaveBeenCalledTimes(2);
158
+ expect(spy).toHaveBeenCalledTimes(2);
160
159
  });
161
160
  });
162
161
 
@@ -1,9 +1,6 @@
1
- import {
2
- SchedulePolicy as SchedulePolicies,
3
- ClearPolicy as ClearPolicies,
4
- } from "./policies";
1
+ import {SchedulePolicy, ClearPolicy} from "./policies";
5
2
 
6
- import type {IAnimationFrame, SchedulePolicy, ClearPolicy} from "./types";
3
+ import type {IAnimationFrame} from "./types";
7
4
 
8
5
  /**
9
6
  * Encapsulates everything associated with calling requestAnimationFrame/
@@ -22,8 +19,8 @@ export default class AnimationFrame implements IAnimationFrame {
22
19
  * Creates an animation frame request that will invoke the given action.
23
20
  * The request is not made until set is called.
24
21
  *
25
- * @param {(time: DOMHighResTimeStamp) => mixed} action The action to be invoked.
26
- * @param {SchedulePolicy} [schedulePolicy] When SchedulePolicy.Immediately,
22
+ * @param action The action to be invoked.
23
+ * @param [schedulePolicy] When SchedulePolicy.Immediately,
27
24
  * the interval is set immediately on instantiation; otherwise, `set` must be
28
25
  * called to set the interval.
29
26
  * Defaults to `SchedulePolicy.Immediately`.
@@ -31,7 +28,7 @@ export default class AnimationFrame implements IAnimationFrame {
31
28
  */
32
29
  constructor(
33
30
  action: (time: DOMHighResTimeStamp) => unknown,
34
- schedulePolicy: SchedulePolicy = SchedulePolicies.Immediately,
31
+ schedulePolicy: SchedulePolicy = SchedulePolicy.Immediately,
35
32
  ) {
36
33
  if (typeof action !== "function") {
37
34
  throw new Error("Action must be a function");
@@ -39,7 +36,7 @@ export default class AnimationFrame implements IAnimationFrame {
39
36
 
40
37
  this._action = action;
41
38
 
42
- if (schedulePolicy === SchedulePolicies.Immediately) {
39
+ if (schedulePolicy === SchedulePolicy.Immediately) {
43
40
  this.set();
44
41
  }
45
42
  }
@@ -66,10 +63,10 @@ export default class AnimationFrame implements IAnimationFrame {
66
63
  */
67
64
  set(): void {
68
65
  if (this.isSet) {
69
- this.clear(ClearPolicies.Cancel);
66
+ this.clear(ClearPolicy.Cancel);
70
67
  }
71
68
  this._animationFrameId = requestAnimationFrame((time) =>
72
- this.clear(ClearPolicies.Resolve, time),
69
+ this.clear(ClearPolicy.Resolve, time),
73
70
  );
74
71
  }
75
72
 
@@ -79,19 +76,18 @@ export default class AnimationFrame implements IAnimationFrame {
79
76
  * If the request is pending, this cancels that pending request without
80
77
  * invoking the action. If no request is pending, this does nothing.
81
78
  *
82
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
79
+ * @param [policy] When ClearPolicy.Resolve, if the request
83
80
  * was set when called, the request action is invoked after cancelling
84
81
  * the request; otherwise, the pending action is cancelled.
85
82
  * Defaults to `ClearPolicy.Cancel`.
86
- * @param {DOMHighResTimeStamp} [time] Timestamp to pass to the action when
83
+ * @param [time] Timestamp to pass to the action when
87
84
  * ClearPolicy.Resolve is specified. Ignored when ClearPolicy.Cancel is
88
85
  * specified.
89
86
  *
90
- * @returns {void}
91
87
  * @memberof AnimationFrame
92
88
  */
93
89
  clear(
94
- policy: ClearPolicy = ClearPolicies.Cancel,
90
+ policy: ClearPolicy = ClearPolicy.Cancel,
95
91
  time?: DOMHighResTimeStamp,
96
92
  ): void {
97
93
  const animationFrameId = this._animationFrameId;
@@ -100,7 +96,7 @@ export default class AnimationFrame implements IAnimationFrame {
100
96
  return;
101
97
  }
102
98
  cancelAnimationFrame(animationFrameId);
103
- if (policy === ClearPolicies.Resolve) {
99
+ if (policy === ClearPolicy.Resolve) {
104
100
  this._action(time || performance.now());
105
101
  }
106
102
  }
@@ -1,9 +1,6 @@
1
- import {
2
- SchedulePolicy as SchedulePolicies,
3
- ClearPolicy as ClearPolicies,
4
- } from "./policies";
1
+ import {SchedulePolicy, ClearPolicy} from "./policies";
5
2
 
6
- import type {IInterval, SchedulePolicy, ClearPolicy} from "./types";
3
+ import type {IInterval} from "./types";
7
4
 
8
5
  /**
9
6
  * Encapsulates everything associated with calling setInterval/clearInterval,
@@ -15,7 +12,7 @@ import type {IInterval, SchedulePolicy, ClearPolicy} from "./types";
15
12
  * @implements {IInterval}
16
13
  */
17
14
  export default class Interval implements IInterval {
18
- _intervalId: number | null | undefined;
15
+ _intervalId: ReturnType<typeof setInterval> | null | undefined;
19
16
  _action: () => unknown;
20
17
  _intervalMs: number;
21
18
 
@@ -23,10 +20,10 @@ export default class Interval implements IInterval {
23
20
  * Creates an interval that will invoke the given action after
24
21
  * the given period. The interval does not start until set is called.
25
22
  *
26
- * @param {() => mixed} action The action to be invoked each time the
23
+ * @param action The action to be invoked each time the
27
24
  * interval period has passed.
28
- * @param {number} intervalMs The interval period.
29
- * @param {SchedulePolicy} [schedulePolicy] When SchedulePolicy.Immediately,
25
+ * @param intervalMs The interval period.
26
+ * @param [schedulePolicy] When SchedulePolicy.Immediately,
30
27
  * the interval is set immediately on instantiation; otherwise, `set` must be
31
28
  * called to set the interval.
32
29
  * Defaults to `SchedulePolicy.Immediately`.
@@ -35,7 +32,7 @@ export default class Interval implements IInterval {
35
32
  constructor(
36
33
  action: () => unknown,
37
34
  intervalMs: number,
38
- schedulePolicy: SchedulePolicy = SchedulePolicies.Immediately,
35
+ schedulePolicy: SchedulePolicy = SchedulePolicy.Immediately,
39
36
  ) {
40
37
  if (typeof action !== "function") {
41
38
  throw new Error("Action must be a function");
@@ -48,7 +45,7 @@ export default class Interval implements IInterval {
48
45
  this._action = action;
49
46
  this._intervalMs = intervalMs;
50
47
 
51
- if (schedulePolicy === SchedulePolicies.Immediately) {
48
+ if (schedulePolicy === SchedulePolicy.Immediately) {
52
49
  this.set();
53
50
  }
54
51
  }
@@ -56,7 +53,7 @@ export default class Interval implements IInterval {
56
53
  /**
57
54
  * Determine if the interval is active or not.
58
55
  *
59
- * @returns {boolean} true if the interval is active, otherwise false.
56
+ * @returns true if the interval is active, otherwise false.
60
57
  * @memberof Interval
61
58
  */
62
59
  get isSet(): boolean {
@@ -73,9 +70,8 @@ export default class Interval implements IInterval {
73
70
  */
74
71
  set(): void {
75
72
  if (this.isSet) {
76
- this.clear(ClearPolicies.Cancel);
73
+ this.clear(ClearPolicy.Cancel);
77
74
  }
78
- // @ts-expect-error [FEI-5019] - TS2322 - Type 'Timer' is not assignable to type 'number'.
79
75
  this._intervalId = setInterval(() => this._action(), this._intervalMs);
80
76
  }
81
77
 
@@ -85,22 +81,21 @@ export default class Interval implements IInterval {
85
81
  * If the interval is active, this cancels that interval. If no interval is
86
82
  * pending, this does nothing.
87
83
  *
88
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
84
+ * @param [policy] When ClearPolicy.Resolve, if the request
89
85
  * was set when called, the request action is invoked after cancelling
90
86
  * the request; otherwise, the pending action is cancelled.
91
87
  * Defaults to `ClearPolicy.Cancel`.
92
88
  *
93
- * @returns {void}
94
89
  * @memberof Interval
95
90
  */
96
- clear(policy: ClearPolicy = ClearPolicies.Cancel): void {
91
+ clear(policy: ClearPolicy = ClearPolicy.Cancel): void {
97
92
  const intervalId = this._intervalId;
98
93
  this._intervalId = null;
99
94
  if (intervalId == null) {
100
95
  return;
101
96
  }
102
97
  clearInterval(intervalId);
103
- if (policy === ClearPolicies.Resolve) {
98
+ if (policy === ClearPolicy.Resolve) {
104
99
  this._action();
105
100
  }
106
101
  }
@@ -1,9 +1,14 @@
1
- export const SchedulePolicy = {
2
- Immediately: "schedule-immediately",
3
- OnDemand: "schedule-on-demand",
4
- } as const;
1
+ export enum SchedulePolicy {
2
+ Immediately = "schedule-immediately",
3
+ OnDemand = "schedule-on-demand",
4
+ }
5
5
 
6
- export const ClearPolicy = {
7
- Resolve: "resolve-on-clear",
8
- Cancel: "cancel-on-clear",
9
- } as const;
6
+ export enum ClearPolicy {
7
+ Resolve = "resolve-on-clear",
8
+ Cancel = "cancel-on-clear",
9
+ }
10
+
11
+ export enum ActionPolicy {
12
+ Reset = "reset",
13
+ Passive = "passive",
14
+ }
@@ -1,9 +1,6 @@
1
- import {
2
- SchedulePolicy as SchedulePolicies,
3
- ClearPolicy as ClearPolicies,
4
- } from "./policies";
1
+ import {SchedulePolicy, ClearPolicy} from "./policies";
5
2
 
6
- import type {ITimeout, SchedulePolicy, ClearPolicy} from "./types";
3
+ import type {ITimeout} from "./types";
7
4
 
8
5
  /**
9
6
  * Encapsulates everything associated with calling setTimeout/clearTimeout, and
@@ -15,7 +12,7 @@ import type {ITimeout, SchedulePolicy, ClearPolicy} from "./types";
15
12
  * @implements {ITimeout}
16
13
  */
17
14
  export default class Timeout implements ITimeout {
18
- _timeoutId: number | null | undefined;
15
+ _timeoutId: ReturnType<typeof setTimeout> | null | undefined;
19
16
  _action: () => unknown;
20
17
  _timeoutMs: number;
21
18
 
@@ -23,10 +20,10 @@ export default class Timeout implements ITimeout {
23
20
  * Creates a timeout that will invoke the given action after
24
21
  * the given period. The timeout does not start until set is called.
25
22
  *
26
- * @param {() => mixed} action The action to be invoked when the timeout
23
+ * @param action The action to be invoked when the timeout
27
24
  * period has passed.
28
- * @param {number} timeoutMs The timeout period.
29
- * @param {SchedulePolicy} [schedulePolicy] When SchedulePolicy.Immediately,
25
+ * @param timeoutMs The timeout period.
26
+ * @param [schedulePolicy] When SchedulePolicy.Immediately,
30
27
  * the timer is set immediately on instantiation; otherwise, `set` must be
31
28
  * called to set the timeout.
32
29
  * Defaults to `SchedulePolicy.Immediately`.
@@ -35,7 +32,7 @@ export default class Timeout implements ITimeout {
35
32
  constructor(
36
33
  action: () => unknown,
37
34
  timeoutMs: number,
38
- schedulePolicy: SchedulePolicy = SchedulePolicies.Immediately,
35
+ schedulePolicy: SchedulePolicy = SchedulePolicy.Immediately,
39
36
  ) {
40
37
  if (typeof action !== "function") {
41
38
  throw new Error("Action must be a function");
@@ -48,7 +45,7 @@ export default class Timeout implements ITimeout {
48
45
  this._action = action;
49
46
  this._timeoutMs = timeoutMs;
50
47
 
51
- if (schedulePolicy === SchedulePolicies.Immediately) {
48
+ if (schedulePolicy === SchedulePolicy.Immediately) {
52
49
  this.set();
53
50
  }
54
51
  }
@@ -56,7 +53,7 @@ export default class Timeout implements ITimeout {
56
53
  /**
57
54
  * Determine if the timeout is set or not.
58
55
  *
59
- * @returns {boolean} true if the timeout is set (aka pending), otherwise
56
+ * @returns true if the timeout is set (aka pending), otherwise
60
57
  * false.
61
58
  * @memberof Timeout
62
59
  */
@@ -75,11 +72,10 @@ export default class Timeout implements ITimeout {
75
72
  */
76
73
  set(): void {
77
74
  if (this.isSet) {
78
- this.clear(ClearPolicies.Cancel);
75
+ this.clear(ClearPolicy.Cancel);
79
76
  }
80
- // @ts-expect-error [FEI-5019] - TS2322 - Type 'Timeout' is not assignable to type 'number'.
81
77
  this._timeoutId = setTimeout(
82
- () => this.clear(ClearPolicies.Resolve),
78
+ () => this.clear(ClearPolicy.Resolve),
83
79
  this._timeoutMs,
84
80
  );
85
81
  }
@@ -90,7 +86,7 @@ export default class Timeout implements ITimeout {
90
86
  * If the timeout is pending, this cancels that pending timeout without
91
87
  * invoking the action. If no timeout is pending, this does nothing.
92
88
  *
93
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
89
+ * @param [policy] When ClearPolicy.Resolve, if the request
94
90
  * was set when called, the request action is invoked after cancelling
95
91
  * the request; otherwise, the pending action is cancelled.
96
92
  * Defaults to `ClearPolicy.Cancel`.
@@ -98,14 +94,14 @@ export default class Timeout implements ITimeout {
98
94
  * @returns {void}
99
95
  * @memberof Timeout
100
96
  */
101
- clear(policy: ClearPolicy = ClearPolicies.Cancel): void {
97
+ clear(policy: ClearPolicy = ClearPolicy.Cancel): void {
102
98
  const timeoutId = this._timeoutId;
103
99
  this._timeoutId = null;
104
100
  if (timeoutId == null) {
105
101
  return;
106
102
  }
107
103
  clearTimeout(timeoutId);
108
- if (policy === ClearPolicies.Resolve) {
104
+ if (policy === ClearPolicy.Resolve) {
109
105
  this._action();
110
106
  }
111
107
  }
package/src/util/types.ts CHANGED
@@ -1,6 +1,4 @@
1
- export type SchedulePolicy = "schedule-immediately" | "schedule-on-demand";
2
-
3
- export type ClearPolicy = "resolve-on-clear" | "cancel-on-clear";
1
+ import * as Policies from "./policies";
4
2
 
5
3
  /**
6
4
  * Encapsulates everything associated with calling setTimeout/clearTimeout, and
@@ -35,14 +33,14 @@ export interface ITimeout {
35
33
  * If the timeout is pending, this cancels that pending timeout. If no
36
34
  * timeout is pending, this does nothing.
37
35
  *
38
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
36
+ * @param [policy] When ClearPolicy.Resolve, if the request
39
37
  * was set when called, the request action is invoked after cancelling
40
38
  * the request; otherwise, the pending action is cancelled.
41
39
  * Defaults to `ClearPolicy.Cancel`.
42
40
  *
43
41
  * @memberof ITimeout
44
42
  */
45
- clear(policy?: ClearPolicy): void;
43
+ clear(policy?: Policies.ClearPolicy): void;
46
44
  }
47
45
 
48
46
  /**
@@ -76,14 +74,14 @@ export interface IInterval {
76
74
  * If the interval is active, this cancels that interval. If the interval
77
75
  * is not active, this does nothing.
78
76
  *
79
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
77
+ * @param [policy] When ClearPolicy.Resolve, if the request
80
78
  * was set when called, the request action is invoked after cancelling
81
79
  * the request; otherwise, the pending action is cancelled.
82
80
  * Defaults to `ClearPolicy.Cancel`.
83
81
  *
84
82
  * @memberof IInterval
85
83
  */
86
- clear(policy?: ClearPolicy): void;
84
+ clear(policy?: Policies.ClearPolicy): void;
87
85
  }
88
86
 
89
87
  /**
@@ -119,19 +117,29 @@ export interface IAnimationFrame {
119
117
  * If the request is pending, this cancels that pending request. If no
120
118
  * request is pending, this does nothing.
121
119
  *
122
- * @param {ClearPolicy} [policy] When ClearPolicy.Resolve, if the request
120
+ * @param [policy] When ClearPolicy.Resolve, if the request
123
121
  * was set when called, the request action is invoked after cancelling
124
122
  * the request; otherwise, the pending action is cancelled.
125
123
  * Defaults to `ClearPolicy.Cancel`.
126
124
  *
127
125
  * @memberof IAnimationFrame
128
126
  */
129
- clear(policy?: ClearPolicy): void;
127
+ clear(policy?: Policies.ClearPolicy): void;
130
128
  }
131
129
 
130
+ /**
131
+ * Options for the scheduling APIs.
132
+ */
132
133
  export type Options = {
133
- schedulePolicy?: SchedulePolicy;
134
- clearPolicy?: ClearPolicy;
134
+ schedulePolicy?: Policies.SchedulePolicy;
135
+ clearPolicy?: Policies.ClearPolicy;
136
+ };
137
+
138
+ /**
139
+ * Options for the hook variants of our scheduling APIs.
140
+ */
141
+ export type HookOptions = Options & {
142
+ actionPolicy?: Policies.ActionPolicy;
135
143
  };
136
144
 
137
145
  /**
@@ -3,9 +3,7 @@
3
3
  "extends": "../tsconfig-shared.json",
4
4
  "compilerOptions": {
5
5
  "outDir": "./dist",
6
- "rootDir": "src",
6
+ "rootDir": "src"
7
7
  },
8
- "references": [
9
- {"path": "../wonder-blocks-button/tsconfig-build.json"},
10
- ]
8
+ "references": []
11
9
  }