( runtime, options, )
| 181 | }; |
| 182 | |
| 183 | export const scrollCommand: RuntimeCommand<ScrollCommandOptions, ScrollCommandResult> = async ( |
| 184 | runtime, |
| 185 | options, |
| 186 | ): Promise<ScrollCommandResult> => { |
| 187 | if (!runtime.backend.scroll) { |
| 188 | throw new AppError('UNSUPPORTED_OPERATION', 'scroll is not supported by this backend'); |
| 189 | } |
| 190 | const target = resolveScrollDirection(options.direction); |
| 191 | const amount = normalizeOptionalPositiveNumber(options.amount, 'scroll amount'); |
| 192 | const pixels = normalizeOptionalPositiveInteger(options.pixels, 'scroll pixels'); |
| 193 | const durationMs = normalizeScrollDurationMs(options.durationMs); |
| 194 | assertExclusiveScrollDistanceInputs( |
| 195 | { amount, pixels }, |
| 196 | 'scroll accepts either amount or pixels, not both', |
| 197 | ); |
| 198 | |
| 199 | const resolved = await resolveScrollTarget(runtime, options); |
| 200 | const backendTarget = |
| 201 | resolved.kind === 'viewport' |
| 202 | ? { kind: 'viewport' as const } |
| 203 | : { kind: 'point' as const, point: requireResolvedPoint(resolved) }; |
| 204 | const scrollBackend = runtime.backend.scroll; |
| 205 | const runScroll = async () => |
| 206 | await scrollBackend(toBackendContext(runtime, options), backendTarget, { |
| 207 | direction: target.direction, |
| 208 | ...(amount !== undefined ? { amount } : {}), |
| 209 | ...(pixels !== undefined ? { pixels } : {}), |
| 210 | ...(durationMs !== undefined ? { durationMs } : {}), |
| 211 | }); |
| 212 | let backendResult: Awaited<ReturnType<NonNullable<typeof runtime.backend.scroll>>> | undefined; |
| 213 | let completedPasses = 0; |
| 214 | if (target.edge) { |
| 215 | const edge = target.edge; |
| 216 | const edgeTarget = buildScrollEdgeTarget(resolved); |
| 217 | const edgeResult = await runScrollEdgePasses({ |
| 218 | edge, |
| 219 | captureState: async (scope) => |
| 220 | await captureRuntimeScrollEdgeState(runtime, options, edge, edgeTarget, scope), |
| 221 | scroll: runScroll, |
| 222 | }); |
| 223 | backendResult = edgeResult.result; |
| 224 | completedPasses = edgeResult.passes; |
| 225 | } else { |
| 226 | backendResult = await runScroll(); |
| 227 | completedPasses = 1; |
| 228 | } |
| 229 | const formattedBackendResult = toBackendResult(backendResult); |
| 230 | const reportedDurationMs = honoredScrollDurationMs(formattedBackendResult); |
| 231 | return { |
| 232 | ...resolved, |
| 233 | direction: target.direction, |
| 234 | ...(target.edge ? { edge: target.edge, passes: completedPasses } : {}), |
| 235 | ...(amount !== undefined ? { amount } : {}), |
| 236 | ...(pixels !== undefined ? { pixels } : {}), |
| 237 | ...(reportedDurationMs !== undefined ? { durationMs: reportedDurationMs } : {}), |
| 238 | ...(formattedBackendResult ? { backendResult: formattedBackendResult } : {}), |
| 239 | ...successText( |
| 240 | formatScrollEdgeMessage(target.direction, target.edge, completedPasses, amount, pixels), |
nothing calls this directly
no test coverage detected