( to: AsyncTo<InferState<T>>, props: RunAsyncProps<T>, state: RunAsyncState<T>, target: T )
| 45 | * or a primitive type for a single animated value. |
| 46 | */ |
| 47 | export function runAsync<T extends AnimationTarget>( |
| 48 | to: AsyncTo<InferState<T>>, |
| 49 | props: RunAsyncProps<T>, |
| 50 | state: RunAsyncState<T>, |
| 51 | target: T |
| 52 | ): AsyncResult<T> { |
| 53 | const { callId, parentId, onRest } = props |
| 54 | const { asyncTo: prevTo, promise: prevPromise } = state |
| 55 | |
| 56 | if (!parentId && to === prevTo && !props.reset) { |
| 57 | return prevPromise! |
| 58 | } |
| 59 | |
| 60 | return (state.promise = (async () => { |
| 61 | state.asyncId = callId |
| 62 | state.asyncTo = to |
| 63 | |
| 64 | // The default props of any `animate` calls. |
| 65 | const defaultProps = getDefaultProps<InferProps<T>>(props, (value, key) => |
| 66 | // The `onRest` prop is only called when the `runAsync` promise is resolved. |
| 67 | key === 'onRest' ? undefined : value |
| 68 | ) |
| 69 | |
| 70 | let preventBail!: () => void |
| 71 | let bail: (error: any) => void |
| 72 | |
| 73 | // This promise is rejected when the animation is interrupted. |
| 74 | const bailPromise = new Promise<void>( |
| 75 | (resolve, reject) => ((preventBail = resolve), (bail = reject)) |
| 76 | ) |
| 77 | |
| 78 | const bailIfEnded = (bailSignal: BailSignal) => { |
| 79 | const bailResult = |
| 80 | // The `cancel` prop or `stop` method was used. |
| 81 | (callId <= (state.cancelId || 0) && getCancelledResult(target)) || |
| 82 | // The async `to` prop was replaced. |
| 83 | (callId !== state.asyncId && getFinishedResult(target, false)) |
| 84 | |
| 85 | if (bailResult) { |
| 86 | bailSignal.result = bailResult |
| 87 | |
| 88 | // Reject the `bailPromise` to ensure the `runAsync` promise |
| 89 | // is not relying on the caller to rethrow the error for us. |
| 90 | bail(bailSignal) |
| 91 | throw bailSignal |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // Safety cap for unterminating async scripts under `skipAnimation`. |
| 96 | // Without animation frames to pace it, `while (true) await next(...)` |
| 97 | // becomes a tight microtask loop that would hang the host. |
| 98 | let skipAnimationCallCount = 0 |
| 99 | const SKIP_ANIMATION_CALL_LIMIT = 1024 |
| 100 | |
| 101 | const animate: any = (arg1: any, arg2?: any) => { |
| 102 | // Create the bail signal outside the returned promise, |
| 103 | // so the generated stack trace is relevant. |
| 104 | const bailSignal = new BailSignal() |
no test coverage detected
searching dependent graphs…