mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Animated: Forward Ref to Component
Summary: Changes `createAnimatedComponent` so that a `ref` assigned to an Animated component will now be forwarded to the internal component. Previously, a ref to the internal component was accessed using the `getNode` method. The `getNode` method is now deprecated and will return the same `ref` but show a deprecation error. Changelog: [General] [Changed] - Refs on an Animated component are now the internal component. The `getNode` call has been deprecated. Reviewed By: TheSavior Differential Revision: D18290474 fbshipit-source-id: 5849809583a17624a89071db8be1282a12caedf3
This commit is contained in:
committed by
Facebook Github Bot
parent
894ee72278
commit
66e72bb4e0
@@ -95,51 +95,33 @@ describe('Animated tests', () => {
|
||||
});
|
||||
|
||||
it('does not detach on updates', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
anim.__detach = jest.fn();
|
||||
const opacity = new Animated.Value(0);
|
||||
opacity.__detach = jest.fn();
|
||||
|
||||
const c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
};
|
||||
c.UNSAFE_componentWillMount();
|
||||
const root = TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
expect(opacity.__detach).not.toBeCalled();
|
||||
|
||||
expect(anim.__detach).not.toBeCalled();
|
||||
c._component = {};
|
||||
c.UNSAFE_componentWillReceiveProps({
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
expect(anim.__detach).not.toBeCalled();
|
||||
root.update(<Animated.View style={{opacity}} />);
|
||||
expect(opacity.__detach).not.toBeCalled();
|
||||
|
||||
c.componentWillUnmount();
|
||||
expect(anim.__detach).toBeCalled();
|
||||
root.unmount();
|
||||
expect(opacity.__detach).toBeCalled();
|
||||
});
|
||||
|
||||
it('stops animation when detached', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const opacity = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
|
||||
const c = new Animated.View();
|
||||
c.props = {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
};
|
||||
c.UNSAFE_componentWillMount();
|
||||
const root = TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
Animated.timing(anim, {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: false,
|
||||
}).start(callback);
|
||||
c._component = {};
|
||||
c.componentWillUnmount();
|
||||
|
||||
expect(callback).toBeCalledWith({finished: false});
|
||||
root.unmount();
|
||||
|
||||
expect(callback).toBeCalledWith({finished: false});
|
||||
});
|
||||
|
||||
@@ -198,7 +180,7 @@ describe('Animated tests', () => {
|
||||
<Animated.View style={{opacity}} />,
|
||||
);
|
||||
|
||||
expect(testRenderer.toJSON()).toMatchSnapshot();
|
||||
expect(testRenderer.toJSON().props.style.opacity).toEqual(0);
|
||||
|
||||
Animated.timing(opacity, {
|
||||
toValue: 1,
|
||||
@@ -206,7 +188,7 @@ describe('Animated tests', () => {
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
|
||||
expect(testRenderer.toJSON()).toMatchSnapshot();
|
||||
expect(testRenderer.toJSON().props.style.opacity).toEqual(1);
|
||||
});
|
||||
|
||||
it('warns if `useNativeDriver` is missing', () => {
|
||||
|
||||
@@ -10,18 +10,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const ClassComponentMock = class {};
|
||||
ClassComponentMock.prototype.isReactComponent = true;
|
||||
|
||||
jest
|
||||
.clearAllMocks()
|
||||
.setMock('../../../Text/Text', ClassComponentMock)
|
||||
.setMock('../../../Components/View/View', ClassComponentMock)
|
||||
.setMock('../../../Image/Image', ClassComponentMock)
|
||||
.setMock('../../../Components/ScrollView/ScrollView', ClassComponentMock)
|
||||
.setMock('../../../Lists/FlatList', ClassComponentMock)
|
||||
.setMock('../../../Lists/SectionList', ClassComponentMock)
|
||||
.setMock('react', {Component: class {}})
|
||||
.mock('../../../BatchedBridge/NativeModules', () => ({
|
||||
NativeAnimatedModule: {},
|
||||
PlatformConstants: {
|
||||
@@ -35,128 +25,107 @@ jest
|
||||
// findNodeHandle is imported from ReactNative so mock that whole module.
|
||||
.setMock('../../../Renderer/shims/ReactNative', {findNodeHandle: () => 1});
|
||||
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
import * as React from 'react';
|
||||
|
||||
const Animated = require('../Animated');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
function createAndMountComponent(ComponentClass, props) {
|
||||
const component = new ComponentClass();
|
||||
component.props = props;
|
||||
component.UNSAFE_componentWillMount();
|
||||
// Simulate that refs were set.
|
||||
component._component = {};
|
||||
component.componentDidMount();
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('Native Animated', () => {
|
||||
const nativeAnimatedModule = require('../NativeAnimatedModule').default;
|
||||
const NativeAnimatedModule = require('../NativeAnimatedModule').default;
|
||||
|
||||
beforeEach(() => {
|
||||
nativeAnimatedModule.addAnimatedEventToView = jest.fn();
|
||||
nativeAnimatedModule.connectAnimatedNodes = jest.fn();
|
||||
nativeAnimatedModule.connectAnimatedNodeToView = jest.fn();
|
||||
nativeAnimatedModule.createAnimatedNode = jest.fn();
|
||||
nativeAnimatedModule.disconnectAnimatedNodeFromView = jest.fn();
|
||||
nativeAnimatedModule.disconnectAnimatedNodes = jest.fn();
|
||||
nativeAnimatedModule.dropAnimatedNode = jest.fn();
|
||||
nativeAnimatedModule.extractAnimatedNodeOffset = jest.fn();
|
||||
nativeAnimatedModule.flattenAnimatedNodeOffset = jest.fn();
|
||||
nativeAnimatedModule.removeAnimatedEventFromView = jest.fn();
|
||||
nativeAnimatedModule.setAnimatedNodeOffset = jest.fn();
|
||||
nativeAnimatedModule.setAnimatedNodeValue = jest.fn();
|
||||
nativeAnimatedModule.startAnimatingNode = jest.fn();
|
||||
nativeAnimatedModule.startListeningToAnimatedNodeValue = jest.fn();
|
||||
nativeAnimatedModule.stopAnimation = jest.fn();
|
||||
nativeAnimatedModule.stopListeningToAnimatedNodeValue = jest.fn();
|
||||
Object.assign(NativeAnimatedModule, {
|
||||
addAnimatedEventToView: jest.fn(),
|
||||
connectAnimatedNodes: jest.fn(),
|
||||
connectAnimatedNodeToView: jest.fn(),
|
||||
createAnimatedNode: jest.fn(),
|
||||
disconnectAnimatedNodeFromView: jest.fn(),
|
||||
disconnectAnimatedNodes: jest.fn(),
|
||||
dropAnimatedNode: jest.fn(),
|
||||
extractAnimatedNodeOffset: jest.fn(),
|
||||
flattenAnimatedNodeOffset: jest.fn(),
|
||||
removeAnimatedEventFromView: jest.fn(),
|
||||
setAnimatedNodeOffset: jest.fn(),
|
||||
setAnimatedNodeValue: jest.fn(),
|
||||
startAnimatingNode: jest.fn(),
|
||||
startListeningToAnimatedNodeValue: jest.fn(),
|
||||
stopAnimation: jest.fn(),
|
||||
stopListeningToAnimatedNodeValue: jest.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('Animated Value', () => {
|
||||
it('proxies `setValue` correctly', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
Animated.timing(anim, {
|
||||
const opacity = new Animated.Value(0);
|
||||
const ref = React.createRef(null);
|
||||
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
|
||||
const c = createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
TestRenderer.create(<Animated.View ref={ref} style={{opacity}} />);
|
||||
|
||||
// We expect `setValue` not to propagate down to `setNativeProps`, otherwise it may try to access `setNativeProps`
|
||||
// via component refs table that we override here.
|
||||
c.refs = {
|
||||
node: {
|
||||
setNativeProps: jest.fn(),
|
||||
},
|
||||
};
|
||||
expect(ref.current).not.toBeNull();
|
||||
jest.spyOn(ref.current, 'setNativeProps');
|
||||
|
||||
anim.setValue(0.5);
|
||||
opacity.setValue(0.5);
|
||||
|
||||
expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
0.5,
|
||||
);
|
||||
expect(c.refs.node.setNativeProps).not.toHaveBeenCalled();
|
||||
expect(ref.current.setNativeProps).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set offset', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
anim.setOffset(10);
|
||||
anim.__makeNative();
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const opacity = new Animated.Value(0);
|
||||
opacity.setOffset(10);
|
||||
opacity.__makeNative();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'value', value: 0, offset: 10},
|
||||
);
|
||||
anim.setOffset(20);
|
||||
expect(nativeAnimatedModule.setAnimatedNodeOffset).toBeCalledWith(
|
||||
opacity.setOffset(20);
|
||||
expect(NativeAnimatedModule.setAnimatedNodeOffset).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
20,
|
||||
);
|
||||
});
|
||||
|
||||
it('should flatten offset', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
anim.__makeNative();
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const opacity = new Animated.Value(0);
|
||||
opacity.__makeNative();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'value', value: 0, offset: 0},
|
||||
);
|
||||
anim.flattenOffset();
|
||||
expect(nativeAnimatedModule.flattenAnimatedNodeOffset).toBeCalledWith(
|
||||
opacity.flattenOffset();
|
||||
expect(NativeAnimatedModule.flattenAnimatedNodeOffset).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
|
||||
it('should extract offset', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
anim.__makeNative();
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const opacity = new Animated.Value(0);
|
||||
opacity.__makeNative();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'value', value: 0, offset: 0},
|
||||
);
|
||||
anim.extractOffset();
|
||||
expect(nativeAnimatedModule.extractAnimatedNodeOffset).toBeCalledWith(
|
||||
opacity.extractOffset();
|
||||
expect(NativeAnimatedModule.extractAnimatedNodeOffset).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
@@ -169,7 +138,7 @@ describe('Native Animated', () => {
|
||||
const listener = jest.fn();
|
||||
const id = value1.addListener(listener);
|
||||
expect(
|
||||
nativeAnimatedModule.startListeningToAnimatedNodeValue,
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue,
|
||||
).toHaveBeenCalledWith(value1.__getNativeTag());
|
||||
|
||||
NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
|
||||
@@ -190,7 +159,7 @@ describe('Native Animated', () => {
|
||||
|
||||
value1.removeListener(id);
|
||||
expect(
|
||||
nativeAnimatedModule.stopListeningToAnimatedNodeValue,
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue,
|
||||
).toHaveBeenCalledWith(value1.__getNativeTag());
|
||||
|
||||
NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
|
||||
@@ -207,7 +176,7 @@ describe('Native Animated', () => {
|
||||
const listener = jest.fn();
|
||||
[1, 2, 3, 4].forEach(() => value1.addListener(listener));
|
||||
expect(
|
||||
nativeAnimatedModule.startListeningToAnimatedNodeValue,
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue,
|
||||
).toHaveBeenCalledWith(value1.__getNativeTag());
|
||||
|
||||
NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
|
||||
@@ -219,7 +188,7 @@ describe('Native Animated', () => {
|
||||
|
||||
value1.removeAllListeners();
|
||||
expect(
|
||||
nativeAnimatedModule.stopListeningToAnimatedNodeValue,
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue,
|
||||
).toHaveBeenCalledWith(value1.__getNativeTag());
|
||||
|
||||
NativeAnimatedHelper.nativeEventEmitter.emit('onAnimatedValueUpdate', {
|
||||
@@ -237,8 +206,9 @@ describe('Native Animated', () => {
|
||||
const event = Animated.event([{nativeEvent: {state: {foo: value}}}], {
|
||||
useNativeDriver: true,
|
||||
});
|
||||
const c = createAndMountComponent(Animated.View, {onTouchMove: event});
|
||||
expect(nativeAnimatedModule.addAnimatedEventToView).toBeCalledWith(
|
||||
|
||||
const root = TestRenderer.create(<Animated.View onTouchMove={event} />);
|
||||
expect(NativeAnimatedModule.addAnimatedEventToView).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
'onTouchMove',
|
||||
{
|
||||
@@ -247,8 +217,11 @@ describe('Native Animated', () => {
|
||||
},
|
||||
);
|
||||
|
||||
c.componentWillUnmount();
|
||||
expect(nativeAnimatedModule.removeAnimatedEventFromView).toBeCalledWith(
|
||||
expect(
|
||||
NativeAnimatedModule.removeAnimatedEventFromView,
|
||||
).not.toHaveBeenCalled();
|
||||
root.unmount();
|
||||
expect(NativeAnimatedModule.removeAnimatedEventFromView).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
'onTouchMove',
|
||||
value.__getNativeTag(),
|
||||
@@ -261,10 +234,20 @@ describe('Native Animated', () => {
|
||||
const event = Animated.event([{notNativeEvent: {foo: value}}], {
|
||||
useNativeDriver: true,
|
||||
});
|
||||
expect(() =>
|
||||
createAndMountComponent(Animated.View, {onTouchMove: event}),
|
||||
).toThrowError(/nativeEvent/);
|
||||
expect(nativeAnimatedModule.addAnimatedEventToView).not.toBeCalled();
|
||||
|
||||
jest.spyOn(console, 'error').mockImplementationOnce((...args) => {
|
||||
if (args[0].startsWith('The above error occurred in the')) {
|
||||
return;
|
||||
}
|
||||
console.errorDebug(...args);
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
TestRenderer.create(<Animated.View onTouchMove={event} />);
|
||||
}).toThrowError(/nativeEvent/);
|
||||
expect(NativeAnimatedModule.addAnimatedEventToView).not.toBeCalled();
|
||||
|
||||
console.error.mockRestore();
|
||||
});
|
||||
|
||||
it('should call listeners', () => {
|
||||
@@ -284,27 +267,21 @@ describe('Native Animated', () => {
|
||||
|
||||
describe('Animated Graph', () => {
|
||||
it('creates and detaches nodes', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const c = createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const opacity = new Animated.Value(0);
|
||||
const root = TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
Animated.timing(anim, {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
|
||||
c.componentWillUnmount();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toHaveBeenCalledTimes(3);
|
||||
expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toHaveBeenCalledTimes(3);
|
||||
expect(NativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(
|
||||
2,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -317,34 +294,37 @@ describe('Native Animated', () => {
|
||||
);
|
||||
|
||||
expect(
|
||||
nativeAnimatedModule.disconnectAnimatedNodes,
|
||||
NativeAnimatedModule.disconnectAnimatedNodes,
|
||||
).not.toHaveBeenCalled();
|
||||
expect(NativeAnimatedModule.dropAnimatedNode).not.toHaveBeenCalled();
|
||||
|
||||
root.unmount();
|
||||
|
||||
expect(
|
||||
NativeAnimatedModule.disconnectAnimatedNodes,
|
||||
).toHaveBeenCalledTimes(2);
|
||||
expect(nativeAnimatedModule.dropAnimatedNode).toHaveBeenCalledTimes(3);
|
||||
expect(NativeAnimatedModule.dropAnimatedNode).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('sends a valid description for value, style and props nodes', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const opacity = new Animated.Value(0);
|
||||
TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
Animated.timing(anim, {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'value', value: 0, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'style', style: {opacity: expect.any(Number)}},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'props', props: {style: expect.any(Number)}},
|
||||
);
|
||||
@@ -356,31 +336,29 @@ describe('Native Animated', () => {
|
||||
first.__makeNative();
|
||||
second.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.add(first, second),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.add(first, second)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'addition', input: expect.any(Array)},
|
||||
);
|
||||
const additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const additionCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'addition',
|
||||
);
|
||||
expect(additionCalls.length).toBe(1);
|
||||
const additionCall = additionCalls[0];
|
||||
const additionNodeTag = additionCall[0];
|
||||
const additionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const additionConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === additionNodeTag,
|
||||
);
|
||||
expect(additionConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
additionCall[1].input[0],
|
||||
{type: 'value', value: 1, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
additionCall[1].input[1],
|
||||
{type: 'value', value: 2, offset: 0},
|
||||
);
|
||||
@@ -392,31 +370,29 @@ describe('Native Animated', () => {
|
||||
first.__makeNative();
|
||||
second.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.subtract(first, second),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.subtract(first, second)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'subtraction', input: expect.any(Array)},
|
||||
);
|
||||
const subtractionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const subtractionCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'subtraction',
|
||||
);
|
||||
expect(subtractionCalls.length).toBe(1);
|
||||
const subtractionCall = subtractionCalls[0];
|
||||
const subtractionNodeTag = subtractionCall[0];
|
||||
const subtractionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const subtractionConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === subtractionNodeTag,
|
||||
);
|
||||
expect(subtractionConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
subtractionCall[1].input[0],
|
||||
{type: 'value', value: 2, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
subtractionCall[1].input[1],
|
||||
{type: 'value', value: 1, offset: 0},
|
||||
);
|
||||
@@ -428,31 +404,29 @@ describe('Native Animated', () => {
|
||||
first.__makeNative();
|
||||
second.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.multiply(first, second),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.multiply(first, second)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'multiplication', input: expect.any(Array)},
|
||||
);
|
||||
const multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const multiplicationCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'multiplication',
|
||||
);
|
||||
expect(multiplicationCalls.length).toBe(1);
|
||||
const multiplicationCall = multiplicationCalls[0];
|
||||
const multiplicationNodeTag = multiplicationCall[0];
|
||||
const multiplicationConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const multiplicationConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === multiplicationNodeTag,
|
||||
);
|
||||
expect(multiplicationConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
multiplicationCall[1].input[0],
|
||||
{type: 'value', value: 2, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
multiplicationCall[1].input[1],
|
||||
{type: 'value', value: 1, offset: 0},
|
||||
);
|
||||
@@ -464,31 +438,29 @@ describe('Native Animated', () => {
|
||||
first.__makeNative();
|
||||
second.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.divide(first, second),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.divide(first, second)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'division', input: expect.any(Array)},
|
||||
);
|
||||
const divisionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const divisionCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'division',
|
||||
);
|
||||
expect(divisionCalls.length).toBe(1);
|
||||
const divisionCall = divisionCalls[0];
|
||||
const divisionNodeTag = divisionCall[0];
|
||||
const divisionConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const divisionConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === divisionNodeTag,
|
||||
);
|
||||
expect(divisionConnectionCalls.length).toBe(2);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
divisionCall[1].input[0],
|
||||
{type: 'value', value: 4, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
divisionCall[1].input[1],
|
||||
{type: 'value', value: 2, offset: 0},
|
||||
);
|
||||
@@ -498,27 +470,25 @@ describe('Native Animated', () => {
|
||||
const value = new Animated.Value(4);
|
||||
value.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.modulo(value, 4),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.modulo(value, 4)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'modulus', modulus: 4, input: expect.any(Number)},
|
||||
);
|
||||
const moduloCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const moduloCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'modulus',
|
||||
);
|
||||
expect(moduloCalls.length).toBe(1);
|
||||
const moduloCall = moduloCalls[0];
|
||||
const moduloNodeTag = moduloCall[0];
|
||||
const moduloConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const moduloConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === moduloNodeTag,
|
||||
);
|
||||
expect(moduloConnectionCalls.length).toBe(1);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
moduloCall[1].input,
|
||||
{type: 'value', value: 4, offset: 0},
|
||||
);
|
||||
@@ -528,20 +498,22 @@ describe('Native Animated', () => {
|
||||
const value = new Animated.Value(10);
|
||||
value.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: value.interpolate({
|
||||
inputRange: [10, 20],
|
||||
outputRange: [0, 1],
|
||||
}),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View
|
||||
style={{
|
||||
opacity: value.interpolate({
|
||||
inputRange: [10, 20],
|
||||
outputRange: [0, 1],
|
||||
}),
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'value', value: 10, offset: 0},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{
|
||||
type: 'interpolation',
|
||||
@@ -551,29 +523,27 @@ describe('Native Animated', () => {
|
||||
extrapolateRight: 'extend',
|
||||
},
|
||||
);
|
||||
const interpolationNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
const interpolationNodeTag = NativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
call => call[1].type === 'interpolation',
|
||||
)[0];
|
||||
const valueNodeTag = nativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
const valueNodeTag = NativeAnimatedModule.createAnimatedNode.mock.calls.find(
|
||||
call => call[1].type === 'value',
|
||||
)[0];
|
||||
expect(nativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.connectAnimatedNodes).toBeCalledWith(
|
||||
valueNodeTag,
|
||||
interpolationNodeTag,
|
||||
);
|
||||
});
|
||||
|
||||
it('sends a valid graph description for transform nodes', () => {
|
||||
const value = new Animated.Value(0);
|
||||
value.__makeNative();
|
||||
const translateX = new Animated.Value(0);
|
||||
translateX.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
transform: [{translateX: value}, {scale: 2}],
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{transform: [{translateX}, {scale: 2}]}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{
|
||||
type: 'transform',
|
||||
@@ -597,86 +567,86 @@ describe('Native Animated', () => {
|
||||
const value = new Animated.Value(2);
|
||||
value.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: Animated.diffClamp(value, 0, 20),
|
||||
},
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View style={{opacity: Animated.diffClamp(value, 0, 20)}} />,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'diffclamp', input: expect.any(Number), max: 20, min: 0},
|
||||
);
|
||||
const diffClampCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
const diffClampCalls = NativeAnimatedModule.createAnimatedNode.mock.calls.filter(
|
||||
call => call[1].type === 'diffclamp',
|
||||
);
|
||||
expect(diffClampCalls.length).toBe(1);
|
||||
const diffClampCall = diffClampCalls[0];
|
||||
const diffClampNodeTag = diffClampCall[0];
|
||||
const diffClampConnectionCalls = nativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
const diffClampConnectionCalls = NativeAnimatedModule.connectAnimatedNodes.mock.calls.filter(
|
||||
call => call[1] === diffClampNodeTag,
|
||||
);
|
||||
expect(diffClampConnectionCalls.length).toBe(1);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
diffClampCall[1].input,
|
||||
{type: 'value', value: 2, offset: 0},
|
||||
);
|
||||
});
|
||||
|
||||
it("doesn't call into native API if useNativeDriver is set to false", () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const opacity = new Animated.Value(0);
|
||||
|
||||
const c = createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
const root = TestRenderer.create(<Animated.View style={{opacity}} />);
|
||||
|
||||
Animated.timing(anim, {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
|
||||
c.componentWillUnmount();
|
||||
root.unmount();
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).not.toBeCalled();
|
||||
expect(NativeAnimatedModule.createAnimatedNode).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('fails when trying to run non-native animation on native node', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const opacity = new Animated.Value(0);
|
||||
const ref = React.createRef(null);
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
opacity: anim,
|
||||
},
|
||||
});
|
||||
TestRenderer.create(<Animated.View ref={ref} style={{opacity}} />);
|
||||
|
||||
Animated.timing(anim, {
|
||||
// Necessary to simulate the native animation.
|
||||
expect(ref.current).not.toBeNull();
|
||||
ref.current.setNativeProps = jest.fn();
|
||||
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 50,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
jest.runAllTimers();
|
||||
|
||||
Animated.timing(anim, {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 4,
|
||||
duration: 500,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
expect(jest.runAllTimers).toThrow();
|
||||
try {
|
||||
process.env.NODE_ENV = 'development';
|
||||
expect(jest.runAllTimers).toThrow(
|
||||
'Attempting to run JS driven animation on animated node that has ' +
|
||||
'been moved to "native" earlier by starting an animation with ' +
|
||||
'`useNativeDriver: true`',
|
||||
);
|
||||
} finally {
|
||||
process.env.NODE_ENV = 'test';
|
||||
}
|
||||
});
|
||||
|
||||
it('fails for unsupported styles', () => {
|
||||
const anim = new Animated.Value(0);
|
||||
const left = new Animated.Value(0);
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
left: anim,
|
||||
},
|
||||
});
|
||||
TestRenderer.create(<Animated.View style={{left}} />);
|
||||
|
||||
const animation = Animated.timing(anim, {
|
||||
const animation = Animated.timing(left, {
|
||||
toValue: 10,
|
||||
duration: 50,
|
||||
useNativeDriver: true,
|
||||
@@ -686,23 +656,21 @@ describe('Native Animated', () => {
|
||||
|
||||
it('works for any `static` props and styles', () => {
|
||||
// Passing "unsupported" props should work just fine as long as they are not animated
|
||||
const value = new Animated.Value(0);
|
||||
value.__makeNative();
|
||||
const opacity = new Animated.Value(0);
|
||||
opacity.__makeNative();
|
||||
|
||||
createAndMountComponent(Animated.View, {
|
||||
style: {
|
||||
left: 10,
|
||||
top: 20,
|
||||
opacity: value,
|
||||
},
|
||||
removeClippedSubviews: true,
|
||||
});
|
||||
TestRenderer.create(
|
||||
<Animated.View
|
||||
removeClippedSubviews={true}
|
||||
style={{left: 10, opacity, top: 20}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'style', style: {opacity: expect.any(Number)}},
|
||||
);
|
||||
expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.createAnimatedNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
{type: 'props', props: {style: expect.any(Number)}},
|
||||
);
|
||||
@@ -718,7 +686,7 @@ describe('Native Animated', () => {
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -739,7 +707,7 @@ describe('Native Animated', () => {
|
||||
tension: 164,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -764,7 +732,7 @@ describe('Native Animated', () => {
|
||||
mass: 3,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -788,7 +756,7 @@ describe('Native Animated', () => {
|
||||
speed: 10,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -815,7 +783,7 @@ describe('Native Animated', () => {
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{type: 'decay', deceleration: 0.1, velocity: 10, iterations: 1},
|
||||
@@ -834,7 +802,7 @@ describe('Native Animated', () => {
|
||||
{iterations: 10},
|
||||
).start();
|
||||
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{type: 'decay', deceleration: 0.1, velocity: 10, iterations: 10},
|
||||
@@ -851,7 +819,7 @@ describe('Native Animated', () => {
|
||||
});
|
||||
|
||||
animation.start();
|
||||
expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect(NativeAnimatedModule.startAnimatingNode).toBeCalledWith(
|
||||
expect.any(Number),
|
||||
expect.any(Number),
|
||||
{
|
||||
@@ -863,10 +831,10 @@ describe('Native Animated', () => {
|
||||
expect.any(Function),
|
||||
);
|
||||
const animationId =
|
||||
nativeAnimatedModule.startAnimatingNode.mock.calls[0][0];
|
||||
NativeAnimatedModule.startAnimatingNode.mock.calls[0][0];
|
||||
|
||||
animation.stop();
|
||||
expect(nativeAnimatedModule.stopAnimation).toBeCalledWith(animationId);
|
||||
expect(NativeAnimatedModule.stopAnimation).toBeCalledWith(animationId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Animated tests Animated bypasses \`setNativeProps\` in test environments 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"opacity": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Animated tests Animated bypasses \`setNativeProps\` in test environments 2`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
@@ -15,6 +15,7 @@ const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const React = require('react');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const setAndForwardRef = require('../../Utilities/setAndForwardRef');
|
||||
|
||||
export type AnimatedComponentType<Props, Instance> = React.AbstractComponent<
|
||||
any,
|
||||
@@ -116,20 +117,26 @@ function createAnimatedComponent<Props, Instance>(
|
||||
oldPropsAnimated && oldPropsAnimated.__detach();
|
||||
}
|
||||
|
||||
_setComponentRef = c => {
|
||||
this._prevComponent = this._component;
|
||||
this._component = c;
|
||||
};
|
||||
_setComponentRef = setAndForwardRef({
|
||||
getForwardedRef: () => this.props.forwardedRef,
|
||||
setLocalRef: ref => {
|
||||
this._prevComponent = this._component;
|
||||
this._component = ref;
|
||||
|
||||
// A third party library can use getNode()
|
||||
// to get the node reference of the decorated component
|
||||
getNode() {
|
||||
return this._component;
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
this._component.setNativeProps(props);
|
||||
}
|
||||
// TODO: Delete this in a future release.
|
||||
if (ref != null && ref.getNode == null) {
|
||||
ref.getNode = () => {
|
||||
console.warn(
|
||||
'%s: Calling `getNode()` on the ref of an Animated component ' +
|
||||
'is no longer necessary. You can now directly use the ref ' +
|
||||
'instead. This method will be removed in a future release.',
|
||||
ref.constructor.name ?? '<<anonymous>>',
|
||||
);
|
||||
return ref;
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
render() {
|
||||
const props = this._propsAnimated.__getValue();
|
||||
@@ -182,7 +189,14 @@ function createAnimatedComponent<Props, Instance>(
|
||||
}
|
||||
}
|
||||
|
||||
return AnimatedComponent;
|
||||
return React.forwardRef(function AnimatedComponentWrapper(props, ref) {
|
||||
return (
|
||||
<AnimatedComponent
|
||||
{...props}
|
||||
{...(ref == null ? null : {forwardedRef: ref})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = createAnimatedComponent;
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ exports[`LogBoxInspectorSourceMapStatus should render for failed 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
<AnimatedComponent
|
||||
<ForwardRef(AnimatedComponentWrapper)
|
||||
source={
|
||||
Object {
|
||||
"height": 16,
|
||||
@@ -94,7 +94,7 @@ exports[`LogBoxInspectorSourceMapStatus should render for pending 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
<AnimatedComponent
|
||||
<ForwardRef(AnimatedComponentWrapper)
|
||||
source={
|
||||
Object {
|
||||
"height": 16,
|
||||
|
||||
@@ -25,6 +25,8 @@ const {
|
||||
View,
|
||||
} = require('react-native');
|
||||
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
|
||||
const forceTouchAvailable =
|
||||
(Platform.OS === 'ios' && Platform.constants.forceTouchAvailable) || false;
|
||||
|
||||
@@ -299,6 +301,48 @@ class TouchableHitSlop extends React.Component<{}, $FlowFixMeState> {
|
||||
}
|
||||
}
|
||||
|
||||
function TouchableNativeMethodChecker<
|
||||
T: React.AbstractComponent<any, any>,
|
||||
>(props: {|Component: T, name: string|}): React.Node {
|
||||
const [status, setStatus] = useState<?boolean>(null);
|
||||
const ref = useRef<?React.ElementRef<T>>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setStatus(ref.current != null && typeof ref.current.measure === 'function');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={[styles.row, styles.block]}>
|
||||
<props.Component ref={ref}>
|
||||
<View />
|
||||
</props.Component>
|
||||
<Text>
|
||||
{props.name + ': '}
|
||||
{status == null
|
||||
? 'Missing Ref!'
|
||||
: status === true
|
||||
? 'Native Methods Exist'
|
||||
: 'Native Methods Missing!'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function TouchableNativeMethods() {
|
||||
return (
|
||||
<View>
|
||||
<TouchableNativeMethodChecker
|
||||
Component={TouchableHighlight}
|
||||
name="TouchableHighlight"
|
||||
/>
|
||||
<TouchableNativeMethodChecker
|
||||
Component={TouchableOpacity}
|
||||
name="TouchableOpacity"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
class TouchableDisabled extends React.Component<{}> {
|
||||
render() {
|
||||
return (
|
||||
@@ -551,6 +595,13 @@ exports.examples = [
|
||||
return <TouchableHitSlop />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Touchable Native Methods',
|
||||
description: ('Some <Touchable*> components expose native methods like `measure`.': string),
|
||||
render: function(): React.Element<any> {
|
||||
return <TouchableNativeMethods />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Disabled Touchable*',
|
||||
description: ('<Touchable*> components accept disabled prop which prevents ' +
|
||||
|
||||
Reference in New Issue
Block a user