mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-08-15 18:45:06 +00:00
Reorganize internal modules
This commit is contained in:
+2
-2
@@ -7,12 +7,12 @@ global.__DEV__ = true;
|
||||
const mockEmptyObject = {};
|
||||
|
||||
// Make sure snapshots contain the original style objects
|
||||
jest.mock('../dist/cjs/modules/ReactNativePropRegistry', () => ({
|
||||
jest.mock('../dist/cjs/modules/StyleSheet/ReactNativePropRegistry', () => ({
|
||||
register: id => id,
|
||||
getByID: () => mockEmptyObject
|
||||
}));
|
||||
|
||||
jest.mock('../dist/modules/ReactNativePropRegistry', () => ({
|
||||
jest.mock('../dist/modules/StyleSheet/ReactNativePropRegistry', () => ({
|
||||
register: id => id,
|
||||
getByID: () => mockEmptyObject
|
||||
}));
|
||||
|
||||
@@ -12,8 +12,7 @@ import type { ComponentType } from 'react';
|
||||
|
||||
import AppContainer from './AppContainer';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import hydrate from '../../modules/hydrate';
|
||||
import render from '../render';
|
||||
import render, { hydrate } from '../render';
|
||||
import styleResolver from '../StyleSheet/styleResolver';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
||||
import ReactNativePropRegistry from './ReactNativePropRegistry';
|
||||
import flattenStyle from './flattenStyle';
|
||||
|
||||
const absoluteFillObject = {
|
||||
|
||||
-69
@@ -201,72 +201,3 @@ Object {
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode next class names have priority over current inline styles 1`] = `
|
||||
Object {
|
||||
"className": "r-opacity-6dt33c",
|
||||
"style": Object {
|
||||
"opacity": "",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode next inline styles have priority over current inline styles 1`] = `
|
||||
Object {
|
||||
"className": "",
|
||||
"style": Object {
|
||||
"WebkitTransform": "scale(2)",
|
||||
"opacity": 1,
|
||||
"transform": "scale(2)",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode preserves unrelated class names 1`] = `
|
||||
Object {
|
||||
"className": "unknown-class-1 unknown-class-2",
|
||||
"style": Object {},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode preserves unrelated inline styles 1`] = `
|
||||
Object {
|
||||
"className": "",
|
||||
"style": Object {
|
||||
"fontSize": "20px",
|
||||
"opacity": 1,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode when isRTL=true & doLeftAndRightSwapInRTL=false, resolves to non-flipped inline styles 1`] = `
|
||||
Object {
|
||||
"className": "",
|
||||
"style": Object {
|
||||
"marginRight": "10px",
|
||||
"paddingLeft": "10px",
|
||||
"right": "10px",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode when isRTL=true, resolves to flipped classNames 1`] = `
|
||||
Object {
|
||||
"className": "r-left-1u10d71 r-marginRight-zso239",
|
||||
"style": Object {
|
||||
"marginRight": "",
|
||||
"right": "5px",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`StyleSheet/createStyleResolver resolveWithNode when isRTL=true, resolves to flipped inline styles 1`] = `
|
||||
Object {
|
||||
"className": "",
|
||||
"style": Object {
|
||||
"left": "10px",
|
||||
"marginRight": "10px",
|
||||
"right": "5px",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
+1
-70
@@ -1,7 +1,7 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import I18nManager from '../../I18nManager';
|
||||
import ReactNativePropRegistry from '../../../modules/ReactNativePropRegistry';
|
||||
import ReactNativePropRegistry from '../ReactNativePropRegistry';
|
||||
import createStyleResolver from '../createStyleResolver';
|
||||
|
||||
let styleResolver;
|
||||
@@ -75,73 +75,4 @@ describe('StyleSheet/createStyleResolver', () => {
|
||||
expect(styleResolver.resolve({ pointerEvents: 'box-none' })).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveWithNode', () => {
|
||||
let node;
|
||||
|
||||
beforeEach(() => {
|
||||
node = document.createElement('div');
|
||||
});
|
||||
|
||||
test('preserves unrelated class names', () => {
|
||||
node.classList.add('unknown-class-1', 'unknown-class-2');
|
||||
const resolved = styleResolver.resolveWithNode({}, node);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('preserves unrelated inline styles', () => {
|
||||
node.style.cssText = 'font-size: 20px;';
|
||||
const resolved = styleResolver.resolveWithNode({ opacity: 1 }, node);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('next class names have priority over current inline styles', () => {
|
||||
node.style.cssText = 'opacity: 0.5;';
|
||||
const nextStyle = ReactNativePropRegistry.register({ opacity: 1 });
|
||||
const resolved = styleResolver.resolveWithNode(nextStyle, node);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('next inline styles have priority over current inline styles', () => {
|
||||
// note: this also checks for correctly uppercasing the first letter of DOM vendor prefixes
|
||||
node.style.cssText = 'opacity: 0.5; transform: scale(1);';
|
||||
const style = { opacity: 1, transform: [{ scale: 2 }] };
|
||||
const resolved = styleResolver.resolveWithNode(style, node);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('when isRTL=true, resolves to flipped inline styles', () => {
|
||||
// note: DOM state resolved from { marginLeft: 5, left: 5 } in RTL mode
|
||||
node.style.cssText = 'margin-right: 5px; right: 5px;';
|
||||
I18nManager.forceRTL(true);
|
||||
const resolved = styleResolver.resolveWithNode({ marginLeft: 10, right: 10 }, node);
|
||||
I18nManager.forceRTL(false);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('when isRTL=true, resolves to flipped classNames', () => {
|
||||
// note: DOM state resolved from { marginLeft: 5, left: 5 }
|
||||
node.style.cssText = 'margin-right: 5px; right: 5px;';
|
||||
const nextStyle = ReactNativePropRegistry.register({ marginLeft: 10, right: 1 });
|
||||
|
||||
I18nManager.forceRTL(true);
|
||||
const resolved = styleResolver.resolveWithNode(nextStyle, node);
|
||||
I18nManager.forceRTL(false);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('when isRTL=true & doLeftAndRightSwapInRTL=false, resolves to non-flipped inline styles', () => {
|
||||
// note: DOM state resolved from { marginRight 5, right: 5, paddingEnd: 5 }
|
||||
node.style.cssText = 'margin-right: 5px; right: 5px; padding-left: 5px';
|
||||
I18nManager.forceRTL(true);
|
||||
I18nManager.swapLeftAndRightInRTL(false);
|
||||
const resolved = styleResolver.resolveWithNode(
|
||||
{ marginRight: 10, right: 10, paddingEnd: 10 },
|
||||
node
|
||||
);
|
||||
I18nManager.forceRTL(false);
|
||||
I18nManager.swapLeftAndRightInRTL(true);
|
||||
expect(resolved).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,8 +25,6 @@ import initialRules from './initialRules';
|
||||
import modality from './modality';
|
||||
import { STYLE_ELEMENT_ID, STYLE_GROUPS } from './constants';
|
||||
|
||||
const emptyObject = {};
|
||||
|
||||
export default function createStyleResolver() {
|
||||
let inserted, sheet, lookup;
|
||||
const resolved = { css: {}, ltr: {}, rtl: {}, rtlNoSwap: {} };
|
||||
@@ -148,59 +146,6 @@ export default function createStyleResolver() {
|
||||
return finalProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a React Native style object to DOM attributes, accounting for
|
||||
* the existing styles applied to the DOM node.
|
||||
*
|
||||
* To determine the next style, some of the existing DOM state must be
|
||||
* converted back into React Native styles.
|
||||
*/
|
||||
function resolveWithNode(rnStyleNext, node) {
|
||||
function getDeclaration(className) {
|
||||
return lookup.byClassName[className] || emptyObject;
|
||||
}
|
||||
|
||||
const { classList: rdomClassList, style: rdomStyle } = getDOMStyleInfo(node);
|
||||
// Convert the DOM classList back into a React Native form
|
||||
// Preserves unrecognized class names.
|
||||
const { classList: rnClassList, style: rnStyle } = rdomClassList.reduce(
|
||||
(styleProps, className) => {
|
||||
const { prop, value } = getDeclaration(className);
|
||||
if (prop) {
|
||||
styleProps.style[prop] = value;
|
||||
} else {
|
||||
styleProps.classList.push(className);
|
||||
}
|
||||
return styleProps;
|
||||
},
|
||||
{ classList: [], style: {} }
|
||||
);
|
||||
|
||||
// Create next DOM style props from current and next RN styles
|
||||
const { classList: rdomClassListNext, style: rdomStyleNext } = resolve([
|
||||
i18nStyle(rnStyle),
|
||||
rnStyleNext
|
||||
]);
|
||||
|
||||
// Final className
|
||||
// Add the current class names not managed by React Native
|
||||
const className = classListToString(rdomClassListNext.concat(rnClassList));
|
||||
|
||||
// Final style
|
||||
// Next class names take priority over current inline styles
|
||||
const style = { ...rdomStyle };
|
||||
rdomClassListNext.forEach(className => {
|
||||
const { prop } = getDeclaration(className);
|
||||
if (style[prop]) {
|
||||
style[prop] = '';
|
||||
}
|
||||
});
|
||||
// Next inline styles take priority over current inline styles
|
||||
Object.assign(style, rdomStyleNext);
|
||||
|
||||
return { className, style };
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a React Native style object
|
||||
*/
|
||||
@@ -297,8 +242,7 @@ export default function createStyleResolver() {
|
||||
return result;
|
||||
},
|
||||
resolve,
|
||||
sheet,
|
||||
resolveWithNode
|
||||
sheet
|
||||
};
|
||||
}
|
||||
|
||||
@@ -311,26 +255,3 @@ const createCacheKey = id => {
|
||||
};
|
||||
|
||||
const classListToString = list => list.join(' ').trim();
|
||||
|
||||
/**
|
||||
* Copies classList and style data from a DOM node
|
||||
*/
|
||||
const hyphenPattern = /-([a-z])/g;
|
||||
const toCamelCase = str => str.replace(hyphenPattern, m => m[1].toUpperCase());
|
||||
|
||||
const getDOMStyleInfo = node => {
|
||||
const nodeStyle = node.style;
|
||||
const classList = Array.prototype.slice.call(node.classList);
|
||||
const style = {};
|
||||
// DOM style is a CSSStyleDeclaration
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
|
||||
for (let i = 0; i < nodeStyle.length; i += 1) {
|
||||
const property = nodeStyle.item(i);
|
||||
if (property) {
|
||||
// DOM style uses hyphenated prop names and may include vendor prefixes
|
||||
// Transform back into React DOM style.
|
||||
style[toCamelCase(property)] = nodeStyle.getPropertyValue(property);
|
||||
}
|
||||
}
|
||||
return { classList, style };
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
||||
import ReactNativePropRegistry from './ReactNativePropRegistry';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
function getStyle(style) {
|
||||
|
||||
+3
-2
@@ -4,8 +4,9 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { render } from 'react-dom';
|
||||
import { hydrate, render } from 'react-dom';
|
||||
export { hydrate };
|
||||
export default render;
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import createDOMProps from '../createDOMProps';
|
||||
import findNodeHandle from '../../exports/findNodeHandle';
|
||||
import styleResolver from '../../exports/StyleSheet/styleResolver';
|
||||
import UIManager from '../../exports/UIManager';
|
||||
|
||||
type MeasureOnSuccessCallback = (
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
pageX: number,
|
||||
pageY: number
|
||||
) => void;
|
||||
|
||||
type MeasureInWindowOnSuccessCallback = (
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
) => void;
|
||||
|
||||
type MeasureLayoutOnSuccessCallback = (
|
||||
left: number,
|
||||
top: number,
|
||||
width: number,
|
||||
height: number
|
||||
) => void;
|
||||
|
||||
const NativeMethodsMixin = {
|
||||
/**
|
||||
* Removes focus from an input or view. This is the opposite of `focus()`.
|
||||
*/
|
||||
blur() {
|
||||
UIManager.blur(findNodeHandle(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Requests focus for the given input or view.
|
||||
* The exact behavior triggered will depend the type of view.
|
||||
*/
|
||||
focus() {
|
||||
UIManager.focus(findNodeHandle(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the position and dimensions of the view
|
||||
*/
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
UIManager.measure(findNodeHandle(this), callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the location of the given view in the window and returns the
|
||||
* values via an async callback. If the React root view is embedded in
|
||||
* another native view, this will give you the absolute coordinates. If
|
||||
* successful, the callback will be called be called with the following
|
||||
* arguments:
|
||||
*
|
||||
* - x
|
||||
* - y
|
||||
* - width
|
||||
* - height
|
||||
*
|
||||
* Note that these measurements are not available until after the rendering
|
||||
* has been completed.
|
||||
*/
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
|
||||
UIManager.measureInWindow(findNodeHandle(this), callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Measures the view relative to another view (usually an ancestor)
|
||||
*/
|
||||
measureLayout(
|
||||
relativeToNativeNode: Object,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail: () => void
|
||||
) {
|
||||
UIManager.measureLayout(findNodeHandle(this), relativeToNativeNode, onFail, onSuccess);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function sends props straight to the underlying DOM node.
|
||||
* This works as if all styles were set as inline styles. Since a DOM node
|
||||
* may aleady be styled with class names and inline styles, we need to get
|
||||
* the initial styles from the DOM node and merge them with incoming props.
|
||||
*/
|
||||
setNativeProps(nativeProps: Object) {
|
||||
if (!nativeProps) {
|
||||
return;
|
||||
}
|
||||
const node = findNodeHandle(this);
|
||||
if (node) {
|
||||
// Next state is determined by comparison to existing state (in the DOM).
|
||||
// Existing state has already gone through i18n transform
|
||||
const domProps = createDOMProps(null, nativeProps, style =>
|
||||
styleResolver.resolveWithNode(style, node)
|
||||
);
|
||||
UIManager.updateView(node, domProps, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default NativeMethodsMixin;
|
||||
@@ -16,8 +16,6 @@ import React from 'react';
|
||||
class UnimplementedView extends React.Component<*, *> {
|
||||
setNativeProps() {
|
||||
// Do nothing.
|
||||
// This method is required in order to use this view as a Touchable* child.
|
||||
// See ensureComponentIsNative.js for more info
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import debounce from 'debounce';
|
||||
import findNodeHandle from '../../exports/findNodeHandle';
|
||||
|
||||
const emptyObject = {};
|
||||
const registry = {};
|
||||
|
||||
let id = 1;
|
||||
const guid = () => `r-${id++}`;
|
||||
|
||||
let resizeObserver;
|
||||
if (canUseDOM) {
|
||||
if (typeof window.ResizeObserver !== 'undefined') {
|
||||
resizeObserver = new window.ResizeObserver(entries => {
|
||||
entries.forEach(({ target }) => {
|
||||
const instance = registry[target._layoutId];
|
||||
instance && instance._handleLayout();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
|
||||
console.warn(
|
||||
'onLayout relies on ResizeObserver which is not supported by your browser. ' +
|
||||
'Please include a polyfill, e.g., https://github.com/que-etc/resize-observer-polyfill. ' +
|
||||
'Falling back to window.onresize.'
|
||||
);
|
||||
}
|
||||
|
||||
const triggerAll = () => {
|
||||
Object.keys(registry).forEach(key => {
|
||||
const instance = registry[key];
|
||||
instance._handleLayout();
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('resize', debounce(triggerAll, 16), false);
|
||||
}
|
||||
}
|
||||
|
||||
const observe = instance => {
|
||||
const id = guid();
|
||||
registry[id] = instance;
|
||||
|
||||
if (resizeObserver) {
|
||||
const node = findNodeHandle(instance);
|
||||
if (node) {
|
||||
node._layoutId = id;
|
||||
resizeObserver.observe(node);
|
||||
}
|
||||
} else {
|
||||
instance._layoutId = id;
|
||||
instance._handleLayout();
|
||||
}
|
||||
};
|
||||
|
||||
const unobserve = instance => {
|
||||
if (resizeObserver) {
|
||||
const node = findNodeHandle(instance);
|
||||
if (node) {
|
||||
delete registry[node._layoutId];
|
||||
delete node._layoutId;
|
||||
resizeObserver.unobserve(node);
|
||||
}
|
||||
} else {
|
||||
delete registry[instance._layoutId];
|
||||
delete instance._layoutId;
|
||||
}
|
||||
};
|
||||
|
||||
const safeOverride = (original, next) => {
|
||||
if (original) {
|
||||
return function prototypeOverride() {
|
||||
/* eslint-disable prefer-rest-params */
|
||||
original.call(this, arguments);
|
||||
next.call(this, arguments);
|
||||
/* eslint-enable prefer-rest-params */
|
||||
};
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
const applyLayout = Component => {
|
||||
const componentDidMount = Component.prototype.componentDidMount;
|
||||
const componentDidUpdate = Component.prototype.componentDidUpdate;
|
||||
const componentWillUnmount = Component.prototype.componentWillUnmount;
|
||||
|
||||
Component.prototype.componentDidMount = safeOverride(
|
||||
componentDidMount,
|
||||
function componentDidMount() {
|
||||
this._layoutState = emptyObject;
|
||||
this._isMounted = true;
|
||||
if (this.props.onLayout) {
|
||||
observe(this);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentDidUpdate = safeOverride(
|
||||
componentDidUpdate,
|
||||
function componentDidUpdate(prevProps) {
|
||||
if (this.props.onLayout && !prevProps.onLayout) {
|
||||
observe(this);
|
||||
} else if (!this.props.onLayout && prevProps.onLayout) {
|
||||
unobserve(this);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype.componentWillUnmount = safeOverride(
|
||||
componentWillUnmount,
|
||||
function componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
if (this.props.onLayout) {
|
||||
unobserve(this);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Component.prototype._handleLayout = function() {
|
||||
const layout = this._layoutState;
|
||||
const { onLayout } = this.props;
|
||||
|
||||
if (onLayout) {
|
||||
this.measure((x, y, width, height) => {
|
||||
if (this._isMounted) {
|
||||
if (
|
||||
layout.x !== x ||
|
||||
layout.y !== y ||
|
||||
layout.width !== width ||
|
||||
layout.height !== height
|
||||
) {
|
||||
this._layoutState = { x, y, width, height };
|
||||
const nativeEvent = {
|
||||
layout: this._layoutState
|
||||
};
|
||||
Object.defineProperty(nativeEvent, 'target', {
|
||||
enumerable: true,
|
||||
get: () => findNodeHandle(this)
|
||||
});
|
||||
onLayout({ nativeEvent, timeStamp: Date.now() });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return Component;
|
||||
};
|
||||
|
||||
export default applyLayout;
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import NativeMethodsMixin from '../NativeMethodsMixin';
|
||||
|
||||
const applyNativeMethods = Component => {
|
||||
Object.keys(NativeMethodsMixin).forEach(method => {
|
||||
if (!Component.prototype[method]) {
|
||||
Component.prototype[method] = NativeMethodsMixin[method];
|
||||
}
|
||||
});
|
||||
return Component;
|
||||
};
|
||||
|
||||
export default applyNativeMethods;
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
const ensureComponentIsNative = (component: any) => {
|
||||
invariant(
|
||||
component && typeof component.setNativeProps === 'function',
|
||||
'Touchable child must either be native or forward setNativeProps to a native component'
|
||||
);
|
||||
};
|
||||
|
||||
export default ensureComponentIsNative;
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { hydrate } from 'react-dom';
|
||||
export default hydrate;
|
||||
Reference in New Issue
Block a user