mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
Rerender useSwipeTransition when direction changes (#32379)
We can only render one direction at a time with View Transitions. When the direction changes we need to do another render in the new direction (returning previous or next). To determine direction we store the position we started at and anything moving to a lower value (left/up) is "previous" direction (`false`) and anything else is "next" (`true`) direction. For the very first render we won't know which direction you're going since you're still on the initial position. It's useful to start the render to allow the view transition to take control before anything shifts around so we start from the original position. This is not guaranteed though if the render suspends. For now we start the first render by guessing the direction such as if we know that prev/next are the same as current. With the upcoming auto start mode we can guess more accurately there before we start. We can also add explicit APIs to `startGesture` but ideally it wouldn't matter. Ideally we could just start after the first change in direction from the starting point.
This commit is contained in:
parent
70f1d766e8
commit
88479c6fc3
|
|
@ -614,6 +614,7 @@ module.exports = {
|
||||||
KeyframeAnimationOptions: 'readonly',
|
KeyframeAnimationOptions: 'readonly',
|
||||||
GetAnimationsOptions: 'readonly',
|
GetAnimationsOptions: 'readonly',
|
||||||
Animatable: 'readonly',
|
Animatable: 'readonly',
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
|
|
||||||
spyOnDev: 'readonly',
|
spyOnDev: 'readonly',
|
||||||
spyOnDevAndProd: 'readonly',
|
spyOnDevAndProd: 'readonly',
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,12 @@ export default function Page({url, navigate}) {
|
||||||
activeGesture.current = null;
|
activeGesture.current = null;
|
||||||
cancelGesture();
|
cancelGesture();
|
||||||
}
|
}
|
||||||
|
// Reset scroll
|
||||||
|
swipeRecognizer.current.scrollLeft = !show ? 0 : 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
swipeRecognizer.current.scrollLeft = show ? 0 : 10000;
|
swipeRecognizer.current.scrollLeft = !show ? 0 : 10000;
|
||||||
}, [show]);
|
}, [show]);
|
||||||
|
|
||||||
const exclamation = (
|
const exclamation = (
|
||||||
|
|
|
||||||
|
|
@ -508,6 +508,15 @@ export function createViewTransitionInstance(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GestureTimeline = null;
|
||||||
|
|
||||||
|
export function subscribeToGestureDirection(
|
||||||
|
provider: GestureTimeline,
|
||||||
|
directionCallback: (direction: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
throw new Error('useSwipeTransition is not yet supported in react-art.');
|
||||||
|
}
|
||||||
|
|
||||||
export function clearContainer(container) {
|
export function clearContainer(container) {
|
||||||
// TODO Implement this
|
// TODO Implement this
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1478,6 +1478,60 @@ export function createViewTransitionInstance(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GestureTimeline = AnimationTimeline; // TODO: More provider types.
|
||||||
|
|
||||||
|
export function subscribeToGestureDirection(
|
||||||
|
provider: GestureTimeline,
|
||||||
|
directionCallback: (direction: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
const time = provider.currentTime;
|
||||||
|
if (time === null) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot start a gesture with a disconnected AnimationTimeline.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const startTime = typeof time === 'number' ? time : time.value;
|
||||||
|
if (
|
||||||
|
typeof ScrollTimeline === 'function' &&
|
||||||
|
provider instanceof ScrollTimeline
|
||||||
|
) {
|
||||||
|
// For ScrollTimeline we optimize to only update the current time on scroll events.
|
||||||
|
const element = provider.source;
|
||||||
|
const scrollCallback = () => {
|
||||||
|
const newTime = provider.currentTime;
|
||||||
|
if (newTime !== null) {
|
||||||
|
directionCallback(
|
||||||
|
typeof newTime === 'number'
|
||||||
|
? newTime > startTime
|
||||||
|
: newTime.value > startTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
element.addEventListener('scroll', scrollCallback, false);
|
||||||
|
return () => {
|
||||||
|
element.removeEventListener('scroll', scrollCallback, false);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// For other AnimationTimelines, such as DocumentTimeline, we just update every rAF.
|
||||||
|
// TODO: Optimize ViewTimeline using an IntersectionObserver if it becomes common.
|
||||||
|
const rafCallback = () => {
|
||||||
|
const newTime = provider.currentTime;
|
||||||
|
if (newTime !== null) {
|
||||||
|
directionCallback(
|
||||||
|
typeof newTime === 'number'
|
||||||
|
? newTime > startTime
|
||||||
|
: newTime.value > startTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
callbackID = requestAnimationFrame(rafCallback);
|
||||||
|
};
|
||||||
|
let callbackID = requestAnimationFrame(rafCallback);
|
||||||
|
return () => {
|
||||||
|
cancelAnimationFrame(callbackID);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function clearContainer(container: Container): void {
|
export function clearContainer(container: Container): void {
|
||||||
const nodeType = container.nodeType;
|
const nodeType = container.nodeType;
|
||||||
if (nodeType === DOCUMENT_NODE) {
|
if (nodeType === DOCUMENT_NODE) {
|
||||||
|
|
|
||||||
|
|
@ -605,6 +605,15 @@ export function createViewTransitionInstance(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GestureTimeline = null;
|
||||||
|
|
||||||
|
export function subscribeToGestureDirection(
|
||||||
|
provider: GestureTimeline,
|
||||||
|
directionCallback: (direction: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
throw new Error('useSwipeTransition is not yet supported in React Native.');
|
||||||
|
}
|
||||||
|
|
||||||
export function clearContainer(container: Container): void {
|
export function clearContainer(container: Container): void {
|
||||||
// TODO Implement this for React Native
|
// TODO Implement this for React Native
|
||||||
// UIManager does not expose a "remove all" type method.
|
// UIManager does not expose a "remove all" type method.
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ export type FormInstance = Instance;
|
||||||
|
|
||||||
export type ViewTransitionInstance = null | {name: string, ...};
|
export type ViewTransitionInstance = null | {name: string, ...};
|
||||||
|
|
||||||
|
export type GestureTimeline = null;
|
||||||
|
|
||||||
const NO_CONTEXT = {};
|
const NO_CONTEXT = {};
|
||||||
const UPPERCASE_CONTEXT = {};
|
const UPPERCASE_CONTEXT = {};
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
|
@ -794,6 +796,13 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subscribeToGestureDirection(
|
||||||
|
provider: GestureTimeline,
|
||||||
|
directionCallback: (direction: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
return () => {};
|
||||||
|
},
|
||||||
|
|
||||||
resetTextContent(instance: Instance): void {
|
resetTextContent(instance: Instance): void {
|
||||||
instance.text = null;
|
instance.text = null;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -48,3 +48,5 @@ export const hasInstanceAffectedParent = shim;
|
||||||
export const startViewTransition = shim;
|
export const startViewTransition = shim;
|
||||||
export type ViewTransitionInstance = null | {name: string, ...};
|
export type ViewTransitionInstance = null | {name: string, ...};
|
||||||
export const createViewTransitionInstance = shim;
|
export const createViewTransitionInstance = shim;
|
||||||
|
export type GestureTimeline = any;
|
||||||
|
export const subscribeToGestureDirection = shim;
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {FiberRoot} from './ReactInternalTypes';
|
import type {FiberRoot} from './ReactInternalTypes';
|
||||||
import type {GestureProvider} from 'shared/ReactTypes';
|
import type {GestureTimeline} from './ReactFiberConfig';
|
||||||
|
|
||||||
import {GestureLane} from './ReactFiberLane';
|
import {GestureLane} from './ReactFiberLane';
|
||||||
import {ensureRootIsScheduled} from './ReactFiberRootScheduler';
|
import {ensureRootIsScheduled} from './ReactFiberRootScheduler';
|
||||||
|
import {subscribeToGestureDirection} from './ReactFiberConfig';
|
||||||
|
|
||||||
// This type keeps track of any scheduled or active gestures.
|
// This type keeps track of any scheduled or active gestures.
|
||||||
export type ScheduledGesture = {
|
export type ScheduledGesture = {
|
||||||
provider: GestureProvider,
|
provider: GestureTimeline,
|
||||||
count: number, // The number of times this same provider has been started.
|
count: number, // The number of times this same provider has been started.
|
||||||
|
direction: boolean, // false = previous, true = next
|
||||||
|
cancel: () => void, // Cancel the subscription to direction change.
|
||||||
prev: null | ScheduledGesture, // The previous scheduled gesture in the queue for this root.
|
prev: null | ScheduledGesture, // The previous scheduled gesture in the queue for this root.
|
||||||
next: null | ScheduledGesture, // The next scheduled gesture in the queue for this root.
|
next: null | ScheduledGesture, // The next scheduled gesture in the queue for this root.
|
||||||
};
|
};
|
||||||
|
|
||||||
export function scheduleGesture(
|
export function scheduleGesture(
|
||||||
root: FiberRoot,
|
root: FiberRoot,
|
||||||
provider: GestureProvider,
|
provider: GestureTimeline,
|
||||||
|
initialDirection: boolean,
|
||||||
): ScheduledGesture {
|
): ScheduledGesture {
|
||||||
let prev = root.gestures;
|
let prev = root.gestures;
|
||||||
while (prev !== null) {
|
while (prev !== null) {
|
||||||
|
|
@ -39,9 +43,32 @@ export function scheduleGesture(
|
||||||
prev = next;
|
prev = next;
|
||||||
}
|
}
|
||||||
// Add new instance to the end of the queue.
|
// Add new instance to the end of the queue.
|
||||||
|
const cancel = subscribeToGestureDirection(provider, (direction: boolean) => {
|
||||||
|
if (gesture.direction !== direction) {
|
||||||
|
gesture.direction = direction;
|
||||||
|
if (gesture.prev === null && root.gestures !== gesture) {
|
||||||
|
// This gesture is not in the schedule, meaning it was already rendered.
|
||||||
|
// We need to rerender in the new direction. Insert it into the first slot
|
||||||
|
// in case other gestures are queued after the on-going one.
|
||||||
|
const existing = root.gestures;
|
||||||
|
gesture.next = existing;
|
||||||
|
if (existing !== null) {
|
||||||
|
existing.prev = gesture;
|
||||||
|
}
|
||||||
|
root.gestures = gesture;
|
||||||
|
// Schedule the lane on the root. The Fibers will already be marked as
|
||||||
|
// long as the gesture is active on that Hook.
|
||||||
|
root.pendingLanes |= GestureLane;
|
||||||
|
ensureRootIsScheduled(root);
|
||||||
|
}
|
||||||
|
// TODO: If we're currently rendering this gesture, we need to restart it.
|
||||||
|
}
|
||||||
|
});
|
||||||
const gesture: ScheduledGesture = {
|
const gesture: ScheduledGesture = {
|
||||||
provider: provider,
|
provider: provider,
|
||||||
count: 1,
|
count: 1,
|
||||||
|
direction: initialDirection,
|
||||||
|
cancel: cancel,
|
||||||
prev: prev,
|
prev: prev,
|
||||||
next: null,
|
next: null,
|
||||||
};
|
};
|
||||||
|
|
@ -60,8 +87,12 @@ export function cancelScheduledGesture(
|
||||||
): void {
|
): void {
|
||||||
gesture.count--;
|
gesture.count--;
|
||||||
if (gesture.count === 0) {
|
if (gesture.count === 0) {
|
||||||
|
const cancelDirectionSubscription = gesture.cancel;
|
||||||
|
cancelDirectionSubscription();
|
||||||
// Delete the scheduled gesture from the queue.
|
// Delete the scheduled gesture from the queue.
|
||||||
deleteScheduledGesture(root, gesture);
|
deleteScheduledGesture(root, gesture);
|
||||||
|
// TODO: If we're currently rendering this gesture, we need to restart the render
|
||||||
|
// on a different gesture or cancel the render..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
69
packages/react-reconciler/src/ReactFiberHooks.js
vendored
69
packages/react-reconciler/src/ReactFiberHooks.js
vendored
|
|
@ -27,7 +27,7 @@ import type {
|
||||||
import type {Lanes, Lane} from './ReactFiberLane';
|
import type {Lanes, Lane} from './ReactFiberLane';
|
||||||
import type {HookFlags} from './ReactHookEffectTags';
|
import type {HookFlags} from './ReactHookEffectTags';
|
||||||
import type {Flags} from './ReactFiberFlags';
|
import type {Flags} from './ReactFiberFlags';
|
||||||
import type {TransitionStatus} from './ReactFiberConfig';
|
import type {TransitionStatus, GestureTimeline} from './ReactFiberConfig';
|
||||||
import type {ScheduledGesture} from './ReactFiberGestureScheduler';
|
import type {ScheduledGesture} from './ReactFiberGestureScheduler';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -3981,6 +3981,7 @@ type SwipeTransitionGestureUpdate = {
|
||||||
type SwipeTransitionUpdateQueue = {
|
type SwipeTransitionUpdateQueue = {
|
||||||
pending: null | SwipeTransitionGestureUpdate,
|
pending: null | SwipeTransitionGestureUpdate,
|
||||||
dispatch: StartGesture,
|
dispatch: StartGesture,
|
||||||
|
initialDirection: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function startGesture(
|
function startGesture(
|
||||||
|
|
@ -3996,9 +3997,14 @@ function startGesture(
|
||||||
// Noop.
|
// Noop.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const scheduledGesture = scheduleGesture(root, gestureProvider);
|
const gestureTimeline: GestureTimeline = gestureProvider;
|
||||||
|
const scheduledGesture = scheduleGesture(
|
||||||
|
root,
|
||||||
|
gestureTimeline,
|
||||||
|
queue.initialDirection,
|
||||||
|
);
|
||||||
// Add this particular instance to the queue.
|
// Add this particular instance to the queue.
|
||||||
// We add multiple of the same provider even if they get batched so
|
// We add multiple of the same timeline even if they get batched so
|
||||||
// that if we cancel one but not the other we can keep track of this.
|
// that if we cancel one but not the other we can keep track of this.
|
||||||
// Order doesn't matter but we insert in the beginning to avoid two fields.
|
// Order doesn't matter but we insert in the beginning to avoid two fields.
|
||||||
const update: SwipeTransitionGestureUpdate = {
|
const update: SwipeTransitionGestureUpdate = {
|
||||||
|
|
@ -4041,6 +4047,7 @@ function mountSwipeTransition<T>(
|
||||||
const queue: SwipeTransitionUpdateQueue = {
|
const queue: SwipeTransitionUpdateQueue = {
|
||||||
pending: null,
|
pending: null,
|
||||||
dispatch: (null: any),
|
dispatch: (null: any),
|
||||||
|
initialDirection: previous === current,
|
||||||
};
|
};
|
||||||
const startGestureOnHook: StartGesture = (queue.dispatch = (startGesture.bind(
|
const startGestureOnHook: StartGesture = (queue.dispatch = (startGesture.bind(
|
||||||
null,
|
null,
|
||||||
|
|
@ -4062,31 +4069,34 @@ function updateSwipeTransition<T>(
|
||||||
const startGestureOnHook: StartGesture = queue.dispatch;
|
const startGestureOnHook: StartGesture = queue.dispatch;
|
||||||
const rootRenderLanes = getWorkInProgressRootRenderLanes();
|
const rootRenderLanes = getWorkInProgressRootRenderLanes();
|
||||||
let value = current;
|
let value = current;
|
||||||
if (isGestureRender(rootRenderLanes)) {
|
|
||||||
// We're inside a gesture render. We'll traverse the queue to see if
|
|
||||||
// this specific Hook is part of this gesture and, if so, which
|
|
||||||
// direction to render.
|
|
||||||
const root: FiberRoot | null = getWorkInProgressRoot();
|
|
||||||
if (root === null) {
|
|
||||||
throw new Error(
|
|
||||||
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// We assume that the currently rendering gesture is the one first in the queue.
|
|
||||||
const rootRenderGesture = root.gestures;
|
|
||||||
let update = queue.pending;
|
|
||||||
while (update !== null) {
|
|
||||||
if (rootRenderGesture === update.gesture) {
|
|
||||||
// We had a match, meaning we're currently rendering a direction of this
|
|
||||||
// hook for this gesture.
|
|
||||||
// TODO: Determine which direction this gesture is currently rendering.
|
|
||||||
value = previous;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
update = update.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (queue.pending !== null) {
|
if (queue.pending !== null) {
|
||||||
|
if (isGestureRender(rootRenderLanes)) {
|
||||||
|
// We're inside a gesture render. We'll traverse the queue to see if
|
||||||
|
// this specific Hook is part of this gesture and, if so, which
|
||||||
|
// direction to render.
|
||||||
|
const root: FiberRoot | null = getWorkInProgressRoot();
|
||||||
|
if (root === null) {
|
||||||
|
throw new Error(
|
||||||
|
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// We assume that the currently rendering gesture is the one first in the queue.
|
||||||
|
const rootRenderGesture = root.gestures;
|
||||||
|
if (rootRenderGesture !== null) {
|
||||||
|
let update = queue.pending;
|
||||||
|
while (update !== null) {
|
||||||
|
if (rootRenderGesture === update.gesture) {
|
||||||
|
// We had a match, meaning we're currently rendering a direction of this
|
||||||
|
// hook for this gesture.
|
||||||
|
value = rootRenderGesture.direction ? next : previous;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
update = update.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This lane cannot be cleared as long as we have active gestures.
|
||||||
|
markWorkInProgressReceivedUpdate();
|
||||||
|
}
|
||||||
// As long as there are any active gestures we need to leave the lane on
|
// As long as there are any active gestures we need to leave the lane on
|
||||||
// in case we need to render it later. Since a gesture render doesn't commit
|
// in case we need to render it later. Since a gesture render doesn't commit
|
||||||
// the only time it really fully gets cleared is if something else rerenders
|
// the only time it really fully gets cleared is if something else rerenders
|
||||||
|
|
@ -4096,6 +4106,11 @@ function updateSwipeTransition<T>(
|
||||||
GestureLane,
|
GestureLane,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// By default, we don't know which direction we should start until a movement
|
||||||
|
// has happened. However, if one direction has the same value as current we
|
||||||
|
// know that it's probably not that direction since it won't do anything anyway.
|
||||||
|
// TODO: Add an explicit option to provide this.
|
||||||
|
queue.initialDirection = previous === current;
|
||||||
return [value, startGestureOnHook];
|
return [value, startGestureOnHook];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ export opaque type FormInstance = mixed;
|
||||||
export type ViewTransitionInstance = null | {name: string, ...};
|
export type ViewTransitionInstance = null | {name: string, ...};
|
||||||
export opaque type InstanceMeasurement = mixed;
|
export opaque type InstanceMeasurement = mixed;
|
||||||
export type EventResponder = any;
|
export type EventResponder = any;
|
||||||
|
export type GestureTimeline = any;
|
||||||
|
|
||||||
export const rendererVersion = $$$config.rendererVersion;
|
export const rendererVersion = $$$config.rendererVersion;
|
||||||
export const rendererPackageName = $$$config.rendererPackageName;
|
export const rendererPackageName = $$$config.rendererPackageName;
|
||||||
|
|
@ -144,6 +145,8 @@ export const wasInstanceInViewport = $$$config.wasInstanceInViewport;
|
||||||
export const hasInstanceChanged = $$$config.hasInstanceChanged;
|
export const hasInstanceChanged = $$$config.hasInstanceChanged;
|
||||||
export const hasInstanceAffectedParent = $$$config.hasInstanceAffectedParent;
|
export const hasInstanceAffectedParent = $$$config.hasInstanceAffectedParent;
|
||||||
export const startViewTransition = $$$config.startViewTransition;
|
export const startViewTransition = $$$config.startViewTransition;
|
||||||
|
export const subscribeToGestureDirection =
|
||||||
|
$$$config.subscribeToGestureDirection;
|
||||||
export const createViewTransitionInstance =
|
export const createViewTransitionInstance =
|
||||||
$$$config.createViewTransitionInstance;
|
$$$config.createViewTransitionInstance;
|
||||||
export const clearContainer = $$$config.clearContainer;
|
export const clearContainer = $$$config.clearContainer;
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,15 @@ export function getInstanceFromNode(mockNode: Object): Object | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GestureTimeline = null;
|
||||||
|
|
||||||
|
export function subscribeToGestureDirection(
|
||||||
|
provider: GestureTimeline,
|
||||||
|
directionCallback: (direction: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
|
||||||
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
|
export function beforeActiveInstanceBlur(internalInstanceHandle: Object) {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ export type ReactFormState<S, ReferenceId> = [
|
||||||
|
|
||||||
// Intrinsic GestureProvider. This type varies by Environment whether a particular
|
// Intrinsic GestureProvider. This type varies by Environment whether a particular
|
||||||
// renderer supports it.
|
// renderer supports it.
|
||||||
export type GestureProvider = AnimationTimeline; // TODO: More provider types.
|
export type GestureProvider = any;
|
||||||
|
|
||||||
export type StartGesture = (gestureProvider: GestureProvider) => () => void;
|
export type StartGesture = (gestureProvider: GestureProvider) => () => void;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -533,5 +533,8 @@
|
||||||
"545": "The %s tag may only be rendered once.",
|
"545": "The %s tag may only be rendered once.",
|
||||||
"546": "useEffect CRUD overload is not enabled in this build of React.",
|
"546": "useEffect CRUD overload is not enabled in this build of React.",
|
||||||
"547": "startGesture cannot be called during server rendering.",
|
"547": "startGesture cannot be called during server rendering.",
|
||||||
"548": "Finished rendering the gesture lane but there were no pending gestures. React should not have started a render in this case. This is a bug in React."
|
"548": "Finished rendering the gesture lane but there were no pending gestures. React should not have started a render in this case. This is a bug in React.",
|
||||||
|
"549": "Cannot start a gesture with a disconnected AnimationTimeline.",
|
||||||
|
"550": "useSwipeTransition is not yet supported in react-art.",
|
||||||
|
"551": "useSwipeTransition is not yet supported in React Native."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,18 @@ declare interface ConsoleTask {
|
||||||
run<T>(f: () => T): T;
|
run<T>(f: () => T): T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScrollTimelineOptions = {
|
||||||
|
source: Element,
|
||||||
|
axis?: 'block' | 'inline' | 'x' | 'y',
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
declare class ScrollTimeline extends AnimationTimeline {
|
||||||
|
constructor(options?: ScrollTimelineOptions): void;
|
||||||
|
axis: 'block' | 'inline' | 'x' | 'y';
|
||||||
|
source: Element;
|
||||||
|
}
|
||||||
|
|
||||||
// Flow hides the props of React$Element, this overrides it to unhide
|
// Flow hides the props of React$Element, this overrides it to unhide
|
||||||
// them for React internals.
|
// them for React internals.
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ module.exports = {
|
||||||
|
|
||||||
FinalizationRegistry: 'readonly',
|
FinalizationRegistry: 'readonly',
|
||||||
|
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
|
|
||||||
// Vendor specific
|
// Vendor specific
|
||||||
MSApp: 'readonly',
|
MSApp: 'readonly',
|
||||||
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ module.exports = {
|
||||||
Reflect: 'readonly',
|
Reflect: 'readonly',
|
||||||
globalThis: 'readonly',
|
globalThis: 'readonly',
|
||||||
FinalizationRegistry: 'readonly',
|
FinalizationRegistry: 'readonly',
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
// Vendor specific
|
// Vendor specific
|
||||||
MSApp: 'readonly',
|
MSApp: 'readonly',
|
||||||
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ module.exports = {
|
||||||
|
|
||||||
FinalizationRegistry: 'readonly',
|
FinalizationRegistry: 'readonly',
|
||||||
|
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
|
|
||||||
// Vendor specific
|
// Vendor specific
|
||||||
MSApp: 'readonly',
|
MSApp: 'readonly',
|
||||||
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ module.exports = {
|
||||||
|
|
||||||
FinalizationRegistry: 'readonly',
|
FinalizationRegistry: 'readonly',
|
||||||
|
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
|
|
||||||
// Vendor specific
|
// Vendor specific
|
||||||
MSApp: 'readonly',
|
MSApp: 'readonly',
|
||||||
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ module.exports = {
|
||||||
|
|
||||||
FinalizationRegistry: 'readonly',
|
FinalizationRegistry: 'readonly',
|
||||||
|
|
||||||
|
ScrollTimeline: 'readonly',
|
||||||
|
|
||||||
// Vendor specific
|
// Vendor specific
|
||||||
MSApp: 'readonly',
|
MSApp: 'readonly',
|
||||||
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
__REACT_DEVTOOLS_GLOBAL_HOOK__: 'readonly',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user