mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-22 11:16:55 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d994a25017 | ||
|
|
756df70154 | ||
|
|
f0b06419f9 | ||
|
|
60ff75705e | ||
|
|
5e8ad67296 | ||
|
|
ba24a882be | ||
|
|
c7686209cd | ||
|
|
f1b281ae32 | ||
|
|
b676fbd5e0 | ||
|
|
51aef6c791 | ||
|
|
ae9a9cde5f | ||
|
|
beb907b180 | ||
|
|
a3362e1f38 | ||
|
|
64d2d34367 | ||
|
|
d83cd45b6f | ||
|
|
227971d22c | ||
|
|
4822cf4620 | ||
|
|
91e4528eac | ||
|
|
1ee64d8285 | ||
|
|
66a4c13bf3 | ||
|
|
9012e98ba7 | ||
|
|
046e01dfa9 | ||
|
|
6e71e1e058 | ||
|
|
d5a9f3e779 | ||
|
|
f16f5f21ce |
@@ -144,6 +144,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
|||||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||||
* [reactxp](https://github.com/microsoft/reactxp)
|
* [reactxp](https://github.com/microsoft/reactxp)
|
||||||
* [react-web](https://github.com/taobaofed/react-web)
|
* [react-web](https://github.com/taobaofed/react-web)
|
||||||
|
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ When `false`, the text is not selectable.
|
|||||||
+ `textAlign`
|
+ `textAlign`
|
||||||
+ `textAlignVertical`
|
+ `textAlignVertical`
|
||||||
+ `textDecorationLine`
|
+ `textDecorationLine`
|
||||||
|
+ `textIndent` ‡
|
||||||
+ `textOverflow` ‡
|
+ `textOverflow` ‡
|
||||||
+ `textRendering` ‡
|
+ `textRendering` ‡
|
||||||
+ `textShadowColor`
|
+ `textShadowColor`
|
||||||
|
|||||||
@@ -186,16 +186,30 @@ Controls whether the View can be the target of touch events. The enhanced
|
|||||||
+ `borderRightWidth`
|
+ `borderRightWidth`
|
||||||
+ `borderTopWidth`
|
+ `borderTopWidth`
|
||||||
+ `bottom`
|
+ `bottom`
|
||||||
+ `boxShadow`
|
+ `boxShadow` ‡
|
||||||
+ `boxSizing`
|
+ `boxSizing`
|
||||||
|
+ `clip` ‡
|
||||||
+ `cursor` ‡
|
+ `cursor` ‡
|
||||||
+ `display`
|
+ `display`
|
||||||
|
+ `filter` ‡
|
||||||
+ `flex` (number)
|
+ `flex` (number)
|
||||||
+ `flexBasis`
|
+ `flexBasis`
|
||||||
+ `flexDirection`
|
+ `flexDirection`
|
||||||
+ `flexGrow`
|
+ `flexGrow`
|
||||||
+ `flexShrink`
|
+ `flexShrink`
|
||||||
+ `flexWrap`
|
+ `flexWrap`
|
||||||
|
+ `gridAutoColumns` ‡
|
||||||
|
+ `gridAutoFlow` ‡
|
||||||
|
+ `gridAutoRows` ‡
|
||||||
|
+ `gridColumnEnd` ‡
|
||||||
|
+ `gridColumnGap` ‡
|
||||||
|
+ `gridColumnStart` ‡
|
||||||
|
+ `gridRowEnd` ‡
|
||||||
|
+ `gridRowGap` ‡
|
||||||
|
+ `gridRowStart` ‡
|
||||||
|
+ `gridTemplateColumns` ‡
|
||||||
|
+ `gridTemplateRows` ‡
|
||||||
|
+ `gridTemplateAreas` ‡
|
||||||
+ `height`
|
+ `height`
|
||||||
+ `justifyContent`
|
+ `justifyContent`
|
||||||
+ `left`
|
+ `left`
|
||||||
@@ -228,6 +242,10 @@ Controls whether the View can be the target of touch events. The enhanced
|
|||||||
+ `perspectiveOrigin` ‡
|
+ `perspectiveOrigin` ‡
|
||||||
+ `position`
|
+ `position`
|
||||||
+ `right`
|
+ `right`
|
||||||
|
+ `shadowColor`
|
||||||
|
+ `shadowOffset`
|
||||||
|
+ `shadowOpacity`
|
||||||
|
+ `shadowRadius`
|
||||||
+ `top`
|
+ `top`
|
||||||
+ `transform`
|
+ `transform`
|
||||||
+ `transformOrigin` ‡
|
+ `transformOrigin` ‡
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
|
It is recommended that your application provide a `Promise` and `Array.from`
|
||||||
|
polyfill.
|
||||||
|
|
||||||
## Webpack and Babel
|
## Webpack and Babel
|
||||||
|
|
||||||
[Webpack](webpack.js.org) is a popular build tool for web apps. Below is an
|
[Webpack](webpack.js.org) is a popular build tool for web apps. Below is an
|
||||||
@@ -58,7 +61,7 @@ module.exports = {
|
|||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify('production')
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
})
|
})
|
||||||
},
|
],
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
// Maps the 'react-native' import to 'react-native-web'.
|
// Maps the 'react-native' import to 'react-native-web'.
|
||||||
@@ -73,6 +76,10 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A more complex example setup for web apps can be found in various starter kits
|
||||||
|
(e.g., create-react-app and
|
||||||
|
[react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack))
|
||||||
|
|
||||||
Please refer to the Webpack documentation for more information.
|
Please refer to the Webpack documentation for more information.
|
||||||
|
|
||||||
## Jest
|
## Jest
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'react-native': path.join(__dirname, '../../src')
|
'react-native': path.join(__dirname, '../../src/module')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-native-web",
|
"name": "react-native-web",
|
||||||
"version": "0.0.85",
|
"version": "0.0.90",
|
||||||
"description": "React Native for Web",
|
"description": "React Native for Web",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"array-find-index": "^1.0.2",
|
"array-find-index": "^1.0.2",
|
||||||
"babel-runtime": "^6.23.0",
|
"babel-runtime": "^6.23.0",
|
||||||
"create-react-class": "^15.5.2",
|
"create-react-class": "^15.5.2",
|
||||||
"debounce": "^1.0.0",
|
"debounce": "1.0.2",
|
||||||
"deep-assign": "^2.0.0",
|
"deep-assign": "^2.0.0",
|
||||||
"fbjs": "^0.8.8",
|
"fbjs": "^0.8.8",
|
||||||
"hyphenate-style-name": "^1.0.2",
|
"hyphenate-style-name": "^1.0.2",
|
||||||
@@ -42,19 +42,19 @@
|
|||||||
"babel-core": "^6.24.1",
|
"babel-core": "^6.24.1",
|
||||||
"babel-eslint": "^7.2.2",
|
"babel-eslint": "^7.2.2",
|
||||||
"babel-loader": "^6.4.1",
|
"babel-loader": "^6.4.1",
|
||||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.0",
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.2",
|
||||||
"babel-preset-react-native": "^1.9.1",
|
"babel-preset-react-native": "^1.9.1",
|
||||||
"del-cli": "^0.2.1",
|
"del-cli": "^0.2.1",
|
||||||
"enzyme": "^2.8.2",
|
"enzyme": "^2.8.2",
|
||||||
"enzyme-to-json": "^1.5.1",
|
"enzyme-to-json": "^1.5.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-config-prettier": "^1.6.0",
|
"eslint-config-prettier": "^1.7.0",
|
||||||
"eslint-plugin-promise": "^3.5.0",
|
"eslint-plugin-promise": "^3.5.0",
|
||||||
"eslint-plugin-react": "^6.10.3",
|
"eslint-plugin-react": "^6.10.3",
|
||||||
"file-loader": "^0.11.1",
|
"file-loader": "^0.11.1",
|
||||||
"jest": "^19.0.2",
|
"jest": "^19.0.2",
|
||||||
"node-libs-browser": "^0.5.3",
|
"node-libs-browser": "^0.5.3",
|
||||||
"prettier": "^1.1.0",
|
"prettier": "^1.2.2",
|
||||||
"react": "~15.4.1",
|
"react": "~15.4.1",
|
||||||
"react-addons-test-utils": "~15.4.1",
|
"react-addons-test-utils": "~15.4.1",
|
||||||
"react-dom": "~15.4.1",
|
"react-dom": "~15.4.1",
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ const AppStates = {
|
|||||||
const listeners = [];
|
const listeners = [];
|
||||||
|
|
||||||
class AppState {
|
class AppState {
|
||||||
static isSupported = ExecutionEnvironment.canUseDOM && document.visibilityState;
|
static isAvailable = ExecutionEnvironment.canUseDOM && document.visibilityState;
|
||||||
|
|
||||||
static get currentState() {
|
static get currentState() {
|
||||||
if (!AppState.isSupported) {
|
if (!AppState.isAvailable) {
|
||||||
return AppState.ACTIVE;
|
return AppState.ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static addEventListener(type: string, handler: Function) {
|
static addEventListener(type: string, handler: Function) {
|
||||||
if (AppState.isSupported) {
|
if (AppState.isAvailable) {
|
||||||
invariant(
|
invariant(
|
||||||
EVENT_TYPES.indexOf(type) !== -1,
|
EVENT_TYPES.indexOf(type) !== -1,
|
||||||
'Trying to subscribe to unknown event: "%s"',
|
'Trying to subscribe to unknown event: "%s"',
|
||||||
@@ -44,7 +44,7 @@ class AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static removeEventListener(type: string, handler: Function) {
|
static removeEventListener(type: string, handler: Function) {
|
||||||
if (AppState.isSupported) {
|
if (AppState.isAvailable) {
|
||||||
invariant(
|
invariant(
|
||||||
EVENT_TYPES.indexOf(type) !== -1,
|
EVENT_TYPES.indexOf(type) !== -1,
|
||||||
'Trying to remove listener for unknown event: "%s"',
|
'Trying to remove listener for unknown event: "%s"',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`apis/AsyncStorage mergeLocalStorageItem should have same behavior as react-native 1`] = `
|
exports[`apis/AsyncStorage mergeItem calls callback after setting item 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"age": 31,
|
"age": 31,
|
||||||
"name": "Chris",
|
"name": "Chris",
|
||||||
@@ -11,3 +11,63 @@ Object {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`apis/AsyncStorage mergeItem promise after setting item 1`] = `
|
||||||
|
Object {
|
||||||
|
"age": 31,
|
||||||
|
"name": "Chris",
|
||||||
|
"traits": Object {
|
||||||
|
"eyes": "blue",
|
||||||
|
"hair": "brown",
|
||||||
|
"shoe_size": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/AsyncStorage multiMerge calls callback after setting items 1`] = `
|
||||||
|
Object {
|
||||||
|
"age": 31,
|
||||||
|
"name": "Chris",
|
||||||
|
"traits": Object {
|
||||||
|
"eyes": "blue",
|
||||||
|
"hair": "brown",
|
||||||
|
"shoe_size": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/AsyncStorage multiMerge calls callback after setting items 2`] = `
|
||||||
|
Object {
|
||||||
|
"age": 31,
|
||||||
|
"name": "Amy",
|
||||||
|
"traits": Object {
|
||||||
|
"eyes": "blue",
|
||||||
|
"hair": "black",
|
||||||
|
"shoe_size": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/AsyncStorage multiMerge promise after setting items 1`] = `
|
||||||
|
Object {
|
||||||
|
"age": 31,
|
||||||
|
"name": "Chris",
|
||||||
|
"traits": Object {
|
||||||
|
"eyes": "blue",
|
||||||
|
"hair": "brown",
|
||||||
|
"shoe_size": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/AsyncStorage multiMerge promise after setting items 2`] = `
|
||||||
|
Object {
|
||||||
|
"age": 31,
|
||||||
|
"name": "Amy",
|
||||||
|
"traits": Object {
|
||||||
|
"eyes": "blue",
|
||||||
|
"hair": "black",
|
||||||
|
"shoe_size": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,77 +1,275 @@
|
|||||||
/* eslint-env jasmine, jest */
|
/* eslint-env jasmine, jest */
|
||||||
import AsyncStorage from '..';
|
import AsyncStorage from '..';
|
||||||
|
|
||||||
const waterfall = (fns, cb) => {
|
const originalLocalStorage = window.localStorage;
|
||||||
const _waterfall = (...args) => {
|
|
||||||
const fn = (fns || []).shift();
|
|
||||||
if (typeof fn === 'function') {
|
|
||||||
fn(...args, (err, ...nextArgs) => {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
} else {
|
|
||||||
return _waterfall(...nextArgs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cb(null, ...args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_waterfall();
|
|
||||||
};
|
|
||||||
|
|
||||||
const obj = {};
|
let obj = {};
|
||||||
const mockLocalStorage = {
|
const mockLocalStorage = {
|
||||||
|
length: 0,
|
||||||
|
clear() {
|
||||||
|
obj = {};
|
||||||
|
mockLocalStorage.length = 0;
|
||||||
|
},
|
||||||
getItem(key) {
|
getItem(key) {
|
||||||
return obj[key];
|
return obj[key];
|
||||||
},
|
},
|
||||||
|
key(index) {
|
||||||
|
return Object.keys(obj)[index];
|
||||||
|
},
|
||||||
|
removeItem(key) {
|
||||||
|
delete obj[key];
|
||||||
|
mockLocalStorage.length -= 1;
|
||||||
|
},
|
||||||
setItem(key, value) {
|
setItem(key, value) {
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
|
mockLocalStorage.length += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const originalLocalStorage = window.localStorage;
|
|
||||||
|
const uid123Object = {
|
||||||
|
name: 'Chris',
|
||||||
|
age: 30,
|
||||||
|
traits: { hair: 'brown', eyes: 'green' }
|
||||||
|
};
|
||||||
|
const uid123Delta = {
|
||||||
|
age: 31,
|
||||||
|
traits: { eyes: 'blue', shoe_size: 10 }
|
||||||
|
};
|
||||||
|
const uid124Object = {
|
||||||
|
name: 'Amy',
|
||||||
|
age: 28,
|
||||||
|
traits: { hair: 'black', eyes: 'brown' }
|
||||||
|
};
|
||||||
|
|
||||||
describe('apis/AsyncStorage', () => {
|
describe('apis/AsyncStorage', () => {
|
||||||
describe('mergeLocalStorageItem', () => {
|
beforeEach(() => {
|
||||||
test('should have same behavior as react-native', done => {
|
mockLocalStorage.setItem('UID123', JSON.stringify(uid123Object));
|
||||||
window.localStorage = mockLocalStorage;
|
mockLocalStorage.setItem('UID124', JSON.stringify(uid124Object));
|
||||||
// https://facebook.github.io/react-native/docs/asyncstorage.html
|
window.localStorage = mockLocalStorage;
|
||||||
const UID123_object = {
|
});
|
||||||
name: 'Chris',
|
|
||||||
age: 30,
|
|
||||||
traits: { hair: 'brown', eyes: 'brown' }
|
|
||||||
};
|
|
||||||
const UID123_delta = {
|
|
||||||
age: 31,
|
|
||||||
traits: { eyes: 'blue', shoe_size: 10 }
|
|
||||||
};
|
|
||||||
|
|
||||||
waterfall(
|
afterEach(() => {
|
||||||
[
|
mockLocalStorage.clear();
|
||||||
cb => {
|
window.localStorage = originalLocalStorage;
|
||||||
AsyncStorage.setItem('UID123', JSON.stringify(UID123_object))
|
});
|
||||||
.then(() => cb(null))
|
|
||||||
.catch(cb);
|
describe('clear', () => {
|
||||||
},
|
const assertResult = () => {
|
||||||
cb => {
|
expect(mockLocalStorage.length).toEqual(0);
|
||||||
AsyncStorage.mergeItem('UID123', JSON.stringify(UID123_delta))
|
};
|
||||||
.then(() => cb(null))
|
|
||||||
.catch(cb);
|
test('promise of erased keys', () => {
|
||||||
},
|
expect(mockLocalStorage.length).toEqual(2);
|
||||||
cb => {
|
return AsyncStorage.clear().then(() => {
|
||||||
AsyncStorage.getItem('UID123')
|
assertResult();
|
||||||
.then(result => {
|
});
|
||||||
cb(null, JSON.parse(result));
|
});
|
||||||
})
|
|
||||||
.catch(cb);
|
test('calls callback after erasing keys', done => {
|
||||||
}
|
expect(mockLocalStorage.length).toEqual(2);
|
||||||
],
|
AsyncStorage.clear(err => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getAllKeys', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(result).toEqual(['UID123', 'UID124']);
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise of keys', () => {
|
||||||
|
return AsyncStorage.getAllKeys().then(result => {
|
||||||
|
assertResult(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback with keys', done => {
|
||||||
|
AsyncStorage.getAllKeys((err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult(result);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getItem', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(result).toEqual(JSON.stringify(uid123Object));
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise of item', () => {
|
||||||
|
return AsyncStorage.getItem('UID123').then(result => {
|
||||||
|
assertResult(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback with item', done => {
|
||||||
|
AsyncStorage.getItem('UID123', (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult(result);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('multiGet', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(result).toEqual([
|
||||||
|
['UID123', JSON.stringify(uid123Object)],
|
||||||
|
['UID124', JSON.stringify(uid124Object)]
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise of items', () => {
|
||||||
|
return AsyncStorage.multiGet(['UID123', 'UID124']).then(result => {
|
||||||
|
assertResult(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback with items', done => {
|
||||||
|
AsyncStorage.multiGet(['UID123', 'UID124'], (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult(result);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setItem', () => {
|
||||||
|
const assertResult = () => {
|
||||||
|
expect(mockLocalStorage.getItem('UID123')).toEqual(JSON.stringify(uid123Object));
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting item', () => {
|
||||||
|
return AsyncStorage.setItem('UID123', JSON.stringify(uid123Object)).then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting item', done => {
|
||||||
|
AsyncStorage.setItem('UID123', JSON.stringify(uid123Object), (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('multiSet', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(mockLocalStorage.getItem('UID123')).toEqual(JSON.stringify(uid123Object));
|
||||||
|
expect(mockLocalStorage.getItem('UID124')).toEqual(JSON.stringify(uid124Object));
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting items', () => {
|
||||||
|
return AsyncStorage.multiSet([
|
||||||
|
['UID123', JSON.stringify(uid123Object)],
|
||||||
|
['UID124', JSON.stringify(uid124Object)]
|
||||||
|
]).then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting items', done => {
|
||||||
|
AsyncStorage.multiSet(
|
||||||
|
[['UID123', JSON.stringify(uid123Object)], ['UID124', JSON.stringify(uid124Object)]],
|
||||||
(err, result) => {
|
(err, result) => {
|
||||||
expect(err).toEqual(null);
|
expect(err).toEqual(null);
|
||||||
expect(result).toMatchSnapshot();
|
assertResult();
|
||||||
window.localStorage = originalLocalStorage;
|
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('mergeItem', () => {
|
||||||
|
const assertResult = () => {
|
||||||
|
expect(JSON.parse(mockLocalStorage.getItem('UID123'))).toMatchSnapshot();
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting item', () => {
|
||||||
|
return AsyncStorage.mergeItem('UID123', JSON.stringify(uid123Delta)).then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting item', done => {
|
||||||
|
AsyncStorage.mergeItem('UID123', JSON.stringify(uid123Delta), (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('multiMerge', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(JSON.parse(mockLocalStorage.getItem('UID123'))).toMatchSnapshot();
|
||||||
|
expect(JSON.parse(mockLocalStorage.getItem('UID124'))).toMatchSnapshot();
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting items', () => {
|
||||||
|
return AsyncStorage.multiMerge([
|
||||||
|
['UID123', JSON.stringify(uid123Delta)],
|
||||||
|
['UID124', JSON.stringify(uid123Delta)]
|
||||||
|
]).then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting items', done => {
|
||||||
|
AsyncStorage.multiMerge(
|
||||||
|
[['UID123', JSON.stringify(uid123Delta)], ['UID124', JSON.stringify(uid123Delta)]],
|
||||||
|
(err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeItem', () => {
|
||||||
|
const assertResult = () => {
|
||||||
|
expect(mockLocalStorage.getItem('UID123')).toBeUndefined();
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting item', () => {
|
||||||
|
return AsyncStorage.removeItem('UID123').then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting item', done => {
|
||||||
|
AsyncStorage.removeItem('UID123', (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('multiRemove', () => {
|
||||||
|
const assertResult = result => {
|
||||||
|
expect(mockLocalStorage.getItem('UID123')).toBeUndefined();
|
||||||
|
expect(mockLocalStorage.getItem('UID124')).toBeUndefined();
|
||||||
|
};
|
||||||
|
|
||||||
|
test('promise after setting items', () => {
|
||||||
|
return AsyncStorage.multiRemove(['UID123', 'UID124']).then(() => {
|
||||||
|
assertResult();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('calls callback after setting items', done => {
|
||||||
|
AsyncStorage.multiRemove(['UID123', 'UID124'], (err, result) => {
|
||||||
|
expect(err).toEqual(null);
|
||||||
|
assertResult();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,66 +13,69 @@ const mergeLocalStorageItem = (key, value) => {
|
|||||||
window.localStorage.setItem(key, nextValue);
|
window.localStorage.setItem(key, nextValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createPromise = (getValue, callback) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const value = getValue();
|
||||||
|
if (callback) {
|
||||||
|
callback(null, value);
|
||||||
|
}
|
||||||
|
resolve(value);
|
||||||
|
} catch (err) {
|
||||||
|
if (callback) {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createPromiseAll = (promises, callback, processResult) => {
|
||||||
|
return Promise.all(promises).then(
|
||||||
|
result => {
|
||||||
|
const value = processResult ? processResult(result) : null;
|
||||||
|
callback && callback(null, value);
|
||||||
|
return Promise.resolve(value);
|
||||||
|
},
|
||||||
|
errors => {
|
||||||
|
callback && callback(errors);
|
||||||
|
return Promise.reject(errors);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
class AsyncStorage {
|
class AsyncStorage {
|
||||||
/**
|
/**
|
||||||
* Erases *all* AsyncStorage for the domain.
|
* Erases *all* AsyncStorage for the domain.
|
||||||
*/
|
*/
|
||||||
static clear() {
|
static clear(callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return createPromise(() => {
|
||||||
try {
|
window.localStorage.clear();
|
||||||
window.localStorage.clear();
|
}, callback);
|
||||||
resolve(null);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets *all* keys known to the app, for all callers, libraries, etc.
|
* Gets *all* keys known to the app, for all callers, libraries, etc.
|
||||||
*/
|
*/
|
||||||
static getAllKeys() {
|
static getAllKeys(callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return createPromise(() => {
|
||||||
try {
|
const numberOfKeys = window.localStorage.length;
|
||||||
const numberOfKeys = window.localStorage.length;
|
const keys = [];
|
||||||
const keys = [];
|
for (let i = 0; i < numberOfKeys; i += 1) {
|
||||||
for (let i = 0; i < numberOfKeys; i += 1) {
|
const key = window.localStorage.key(i);
|
||||||
const key = window.localStorage.key(i);
|
keys.push(key);
|
||||||
keys.push(key);
|
|
||||||
}
|
|
||||||
resolve(keys);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
}
|
||||||
});
|
return keys;
|
||||||
|
}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches `key` value.
|
* Fetches `key` value.
|
||||||
*/
|
*/
|
||||||
static getItem(key: string) {
|
static getItem(key: string, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return createPromise(() => {
|
||||||
try {
|
return window.localStorage.getItem(key);
|
||||||
const value = window.localStorage.getItem(key);
|
}, callback);
|
||||||
resolve(value);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges existing value with input value, assuming they are stringified JSON.
|
|
||||||
*/
|
|
||||||
static mergeItem(key: string, value: string) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
mergeLocalStorageItem(key, value);
|
|
||||||
resolve(null);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,13 +84,37 @@ class AsyncStorage {
|
|||||||
*
|
*
|
||||||
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
|
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
|
||||||
*/
|
*/
|
||||||
static multiGet(keys: Array<string>) {
|
static multiGet(keys: Array<string>, callback) {
|
||||||
const promises = keys.map(key => AsyncStorage.getItem(key));
|
const promises = keys.map(key => AsyncStorage.getItem(key));
|
||||||
|
const processResult = result => result.map((value, i) => [keys[i], value]);
|
||||||
|
return createPromiseAll(promises, callback, processResult);
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(
|
/**
|
||||||
result => Promise.resolve(result.map((value, i) => [keys[i], value])),
|
* Sets `value` for `key`.
|
||||||
error => Promise.reject(error)
|
*/
|
||||||
);
|
static setItem(key: string, value: string, callback) {
|
||||||
|
return createPromise(() => {
|
||||||
|
window.localStorage.setItem(key, value);
|
||||||
|
}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an array of key-value array pairs.
|
||||||
|
* multiSet([['k1', 'val1'], ['k2', 'val2']])
|
||||||
|
*/
|
||||||
|
static multiSet(keyValuePairs: Array<Array<string>>, callback) {
|
||||||
|
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
|
||||||
|
return createPromiseAll(promises, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges existing value with input value, assuming they are stringified JSON.
|
||||||
|
*/
|
||||||
|
static mergeItem(key: string, value: string, callback) {
|
||||||
|
return createPromise(() => {
|
||||||
|
mergeLocalStorageItem(key, value);
|
||||||
|
}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,57 +123,26 @@ class AsyncStorage {
|
|||||||
*
|
*
|
||||||
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
|
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
|
||||||
*/
|
*/
|
||||||
static multiMerge(keyValuePairs: Array<Array<string>>) {
|
static multiMerge(keyValuePairs: Array<Array<string>>, callback) {
|
||||||
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
|
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
|
||||||
|
return createPromiseAll(promises, callback);
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null), error => Promise.reject(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all the keys in the `keys` array.
|
|
||||||
*/
|
|
||||||
static multiRemove(keys: Array<string>) {
|
|
||||||
const promises = keys.map(key => AsyncStorage.removeItem(key));
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null), error => Promise.reject(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an array of key-value array pairs.
|
|
||||||
* multiSet([['k1', 'val1'], ['k2', 'val2']])
|
|
||||||
*/
|
|
||||||
static multiSet(keyValuePairs: Array<Array<string>>) {
|
|
||||||
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null), error => Promise.reject(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a `key`
|
* Removes a `key`
|
||||||
*/
|
*/
|
||||||
static removeItem(key: string) {
|
static removeItem(key: string, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return createPromise(() => {
|
||||||
try {
|
return window.localStorage.removeItem(key);
|
||||||
window.localStorage.removeItem(key);
|
}, callback);
|
||||||
resolve(null);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets `value` for `key`.
|
* Delete all the keys in the `keys` array.
|
||||||
*/
|
*/
|
||||||
static setItem(key: string, value: string) {
|
static multiRemove(keys: Array<string>, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
const promises = keys.map(key => AsyncStorage.removeItem(key));
|
||||||
try {
|
return createPromiseAll(promises, callback);
|
||||||
window.localStorage.setItem(key, value);
|
|
||||||
resolve(null);
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,43 @@
|
|||||||
|
/* global window */
|
||||||
|
|
||||||
class Clipboard {
|
class Clipboard {
|
||||||
|
static isSupported() {
|
||||||
|
return (
|
||||||
|
typeof document.queryCommandSupported === 'function' && document.queryCommandSupported('copy')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static getString() {
|
static getString() {
|
||||||
return Promise.resolve('');
|
return Promise.resolve('');
|
||||||
}
|
}
|
||||||
|
|
||||||
static setString(text) {
|
static setString(text) {
|
||||||
let success = false;
|
let success = false;
|
||||||
const textField = document.createElement('textarea');
|
|
||||||
textField.innerText = text;
|
// add the text to a hidden node
|
||||||
document.body.appendChild(textField);
|
const node = document.createElement('span');
|
||||||
textField.select();
|
node.textContent = text;
|
||||||
|
node.style.position = 'absolute';
|
||||||
|
node.style.opacity = '0';
|
||||||
|
document.body.appendChild(node);
|
||||||
|
|
||||||
|
// select the text
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(node);
|
||||||
|
selection.addRange(range);
|
||||||
|
|
||||||
|
// attempt to copy
|
||||||
try {
|
try {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
success = true;
|
success = true;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
document.body.removeChild(textField);
|
|
||||||
|
// remove selection and node
|
||||||
|
selection.removeAllRanges();
|
||||||
|
document.body.removeChild(node);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const Linking = {
|
|||||||
* https://mathiasbynens.github.io/rel-noopener/
|
* https://mathiasbynens.github.io/rel-noopener/
|
||||||
*/
|
*/
|
||||||
const iframeOpen = url => {
|
const iframeOpen = url => {
|
||||||
|
const noOpener = url.indexOf('mailto:') !== 0;
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.style.display = 'none';
|
iframe.style.display = 'none';
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
@@ -36,7 +37,7 @@ const iframeOpen = url => {
|
|||||||
const script = iframeDoc.createElement('script');
|
const script = iframeDoc.createElement('script');
|
||||||
script.text = `
|
script.text = `
|
||||||
window.parent = null; window.top = null; window.frameElement = null;
|
window.parent = null; window.top = null; window.frameElement = null;
|
||||||
var child = window.open("${url}"); child.opener = null;
|
var child = window.open("${url}"); ${noOpener && 'child.opener = null'};
|
||||||
`;
|
`;
|
||||||
iframeDoc.body.appendChild(script);
|
iframeDoc.body.appendChild(script);
|
||||||
document.body.removeChild(iframe);
|
document.body.removeChild(iframe);
|
||||||
|
|||||||
@@ -299,7 +299,8 @@ var PanResponder = {
|
|||||||
PanResponder._initializeGestureState(gestureState);
|
PanResponder._initializeGestureState(gestureState);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
e.nativeEvent.originalEvent && e.nativeEvent.originalEvent.type === 'mousedown'
|
e.nativeEvent.originalEvent &&
|
||||||
|
e.nativeEvent.originalEvent.type === 'mousedown'
|
||||||
) {
|
) {
|
||||||
PanResponder._initializeGestureState(gestureState);
|
PanResponder._initializeGestureState(gestureState);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import flattenArray from '../../modules/flattenArray';
|
|||||||
import flattenStyle from './flattenStyle';
|
import flattenStyle from './flattenStyle';
|
||||||
import I18nManager from '../I18nManager';
|
import I18nManager from '../I18nManager';
|
||||||
import mapKeyValue from '../../modules/mapKeyValue';
|
import mapKeyValue from '../../modules/mapKeyValue';
|
||||||
import prefixInlineStyles from './prefixInlineStyles';
|
import { prefixInlineStyles } from '../../modules/prefixStyles';
|
||||||
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
||||||
import StyleManager from './StyleManager';
|
import StyleManager from './StyleManager';
|
||||||
|
|
||||||
|
const vendorPrefixPattern = /^(webkit|moz|ms)/;
|
||||||
|
|
||||||
const createCacheKey = id => {
|
const createCacheKey = id => {
|
||||||
const prefix = I18nManager.isRTL ? 'rtl' : 'ltr';
|
const prefix = I18nManager.isRTL ? 'rtl' : 'ltr';
|
||||||
return `${prefix}-${id}`;
|
return `${prefix}-${id}`;
|
||||||
@@ -81,36 +83,58 @@ class StyleRegistry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a React Native style object to DOM attributes, accounting for
|
* Resolves a React Native style object to DOM attributes, accounting for
|
||||||
* the existing styles applied to the DOM node
|
* 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.
|
||||||
*/
|
*/
|
||||||
resolveStateful(reactNativeStyle, domClassList) {
|
resolveStateful(rnStyleNext, { classList: domClassList, style: domStyle }) {
|
||||||
const previousReactNativeStyle = {};
|
// Convert the DOM classList back into a React Native form
|
||||||
const preservedClassNames = [];
|
// Preserves unrecognized class names.
|
||||||
|
const { classList: rnClassList, style: rnStyle } = domClassList.reduce(
|
||||||
|
(styleProps, className) => {
|
||||||
|
const { prop, value } = this.styleManager.getDeclaration(className);
|
||||||
|
if (prop) {
|
||||||
|
styleProps.style[prop] = value;
|
||||||
|
} else {
|
||||||
|
styleProps.classList.push(className);
|
||||||
|
}
|
||||||
|
return styleProps;
|
||||||
|
},
|
||||||
|
{ classList: [], style: {} }
|
||||||
|
);
|
||||||
|
|
||||||
// Convert the existing classList to a React Native style and preserve any
|
// DOM style may include vendor prefixes and properties set by other libraries.
|
||||||
// unrecognized classNames.
|
// Preserve it but transform back into React DOM style.
|
||||||
domClassList.forEach(className => {
|
const rdomStyle = Object.keys(domStyle).reduce((acc, styleName) => {
|
||||||
const { prop, value } = this.styleManager.getDeclaration(className);
|
const value = domStyle[styleName];
|
||||||
if (prop) {
|
if (value !== '') {
|
||||||
previousReactNativeStyle[prop] = value;
|
const reactStyleName = vendorPrefixPattern.test(styleName)
|
||||||
} else {
|
? styleName.charAt(0).toUpperCase() + styleName.slice(1)
|
||||||
preservedClassNames.push(className);
|
: styleName;
|
||||||
|
acc[reactStyleName] = value;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// Create next DOM style props from current and next RN styles
|
||||||
|
const { classList: rdomClassListNext, style: rdomStyleNext } = this.resolve([
|
||||||
|
rnStyle,
|
||||||
|
rnStyleNext
|
||||||
|
]);
|
||||||
|
// Next class names take priority over current inline styles
|
||||||
|
const style = { ...rdomStyle };
|
||||||
|
rdomClassListNext.forEach(className => {
|
||||||
|
const { prop } = this.styleManager.getDeclaration(className);
|
||||||
|
if (style[prop]) {
|
||||||
|
style[prop] = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Next inline styles take priority over current inline styles
|
||||||
|
Object.assign(style, rdomStyleNext);
|
||||||
|
// Add the current class names not managed by React Native
|
||||||
|
const className = classListToString(rdomClassListNext.concat(rnClassList));
|
||||||
|
|
||||||
// Resolve the two React Native styles.
|
|
||||||
const { classList, style = {} } = this.resolve([previousReactNativeStyle, reactNativeStyle]);
|
|
||||||
|
|
||||||
// Because this is used in stateful operations we need to remove any
|
|
||||||
// existing inline styles that would override the classNames.
|
|
||||||
classList.forEach(className => {
|
|
||||||
const { prop } = this.styleManager.getDeclaration(className);
|
|
||||||
style[prop] = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
classList.push(preservedClassNames);
|
|
||||||
|
|
||||||
const className = classListToString(classList);
|
|
||||||
return { className, style };
|
return { className, style };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,19 +58,37 @@ describe('apis/StyleSheet/StyleRegistry', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolveStateful', () => {
|
describe('resolveStateful', () => {
|
||||||
// generate a classList to act as pre-existing DOM state
|
test('preserves unrelated class names', () => {
|
||||||
const mockStyle = styleRegistry.register({
|
const domStyleProps = { classList: ['unknown-class-1', 'unknown-class-2'], style: {} };
|
||||||
borderWidth: 0,
|
const domStyleNextProps = styleRegistry.resolveStateful({}, domStyleProps);
|
||||||
borderColor: 'red',
|
expect(domStyleNextProps).toMatchSnapshot();
|
||||||
width: 100
|
|
||||||
});
|
});
|
||||||
const { classList: domClassList } = styleRegistry.resolve(mockStyle);
|
|
||||||
domClassList.unshift('external-className');
|
|
||||||
expect(domClassList).toMatchSnapshot();
|
|
||||||
|
|
||||||
// test result
|
test('preserves unrelated inline styles', () => {
|
||||||
const result = styleRegistry.resolveStateful({ borderWidth: 1, opacity: 1 }, domClassList);
|
const domStyleProps = { classList: [], style: { fontSize: '20px' } };
|
||||||
expect(result).toMatchSnapshot();
|
const domStyleNextProps = styleRegistry.resolveStateful({ opacity: 1 }, domStyleProps);
|
||||||
|
expect(domStyleNextProps).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('next class names have priority over current inline styles', () => {
|
||||||
|
const domStyleProps = { classList: [], style: { opacity: 0.5 } };
|
||||||
|
const nextStyle = styleRegistry.register({ opacity: 1 });
|
||||||
|
const domStyleNextProps = styleRegistry.resolveStateful(nextStyle, domStyleProps);
|
||||||
|
expect(domStyleNextProps).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
|
||||||
|
const domStyleProps = {
|
||||||
|
classList: [],
|
||||||
|
style: { opacity: 0.5, webkitTransform: 'scale(1)', transform: 'scale(1)' }
|
||||||
|
};
|
||||||
|
const domStyleNextProps = styleRegistry.resolveStateful(
|
||||||
|
{ opacity: 1, transform: [{ scale: 2 }] },
|
||||||
|
domStyleProps
|
||||||
|
);
|
||||||
|
expect(domStyleNextProps).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -192,35 +192,39 @@ Object {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`apis/StyleSheet/StyleRegistry resolveStateful 1`] = `
|
exports[`apis/StyleSheet/StyleRegistry resolveStateful next class names have priority over current inline styles 1`] = `
|
||||||
Array [
|
|
||||||
"external-className",
|
|
||||||
"rn-borderTopColor-1gxhl28",
|
|
||||||
"rn-borderRightColor-knoah9",
|
|
||||||
"rn-borderBottomColor-1ani3fp",
|
|
||||||
"rn-borderLeftColor-ribj9x",
|
|
||||||
"rn-borderTopWidth-13yce4e",
|
|
||||||
"rn-borderRightWidth-fnigne",
|
|
||||||
"rn-borderBottomWidth-ndvcnb",
|
|
||||||
"rn-borderLeftWidth-gxnn5r",
|
|
||||||
"rn-width-b8lwoo",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`apis/StyleSheet/StyleRegistry resolveStateful 2`] = `
|
|
||||||
Object {
|
Object {
|
||||||
"className": "rn-borderBottomColor-1ani3fp rn-borderBottomWidth-ndvcnb rn-borderLeftColor-ribj9x rn-borderLeftWidth-gxnn5r rn-borderRightColor-knoah9 rn-borderRightWidth-fnigne rn-borderTopColor-1gxhl28 rn-borderTopWidth-13yce4e rn-width-b8lwoo external-className",
|
"className": "rn-opacity-6dt33c",
|
||||||
"style": Object {
|
"style": Object {
|
||||||
"borderBottomColor": null,
|
"opacity": "",
|
||||||
"borderBottomWidth": null,
|
},
|
||||||
"borderLeftColor": null,
|
}
|
||||||
"borderLeftWidth": null,
|
`;
|
||||||
"borderRightColor": null,
|
|
||||||
"borderRightWidth": null,
|
exports[`apis/StyleSheet/StyleRegistry resolveStateful next inline styles have priority over current inline styles 1`] = `
|
||||||
"borderTopColor": null,
|
Object {
|
||||||
"borderTopWidth": null,
|
"className": "",
|
||||||
"opacity": 1,
|
"style": Object {
|
||||||
"width": null,
|
"WebkitTransform": "scale(2)",
|
||||||
|
"opacity": 1,
|
||||||
|
"transform": "scale(2)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/StyleSheet/StyleRegistry resolveStateful preserves unrelated class names 1`] = `
|
||||||
|
Object {
|
||||||
|
"className": "unknown-class-1 unknown-class-2",
|
||||||
|
"style": Object {},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`apis/StyleSheet/StyleRegistry resolveStateful preserves unrelated inline styles 1`] = `
|
||||||
|
Object {
|
||||||
|
"className": "",
|
||||||
|
"style": Object {
|
||||||
|
"fontSize": "20px",
|
||||||
|
"opacity": 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -3,7 +3,18 @@
|
|||||||
import resolveTransform from '../resolveTransform';
|
import resolveTransform from '../resolveTransform';
|
||||||
|
|
||||||
describe('apis/StyleSheet/resolveTransform', () => {
|
describe('apis/StyleSheet/resolveTransform', () => {
|
||||||
test('transform', () => {
|
// passthrough if transform value is ever a string
|
||||||
|
test('transform string', () => {
|
||||||
|
const resolvedStyle = {};
|
||||||
|
const transform = 'perspective(50px) scaleX(20) translateX(20px) rotate(20deg)';
|
||||||
|
|
||||||
|
const style = { transform };
|
||||||
|
resolveTransform(resolvedStyle, style);
|
||||||
|
|
||||||
|
expect(resolvedStyle).toEqual({ transform });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('transform array', () => {
|
||||||
const resolvedStyle = {};
|
const resolvedStyle = {};
|
||||||
const style = {
|
const style = {
|
||||||
transform: [{ perspective: 50 }, { scaleX: 20 }, { translateX: 20 }, { rotate: '20deg' }]
|
transform: [{ perspective: 50 }, { scaleX: 20 }, { translateX: 20 }, { rotate: '20deg' }]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import hyphenateStyleName from 'hyphenate-style-name';
|
import hyphenateStyleName from 'hyphenate-style-name';
|
||||||
import mapKeyValue from '../../modules/mapKeyValue';
|
import mapKeyValue from '../../modules/mapKeyValue';
|
||||||
import normalizeValue from './normalizeValue';
|
import normalizeValue from './normalizeValue';
|
||||||
import prefixAll from 'inline-style-prefixer/static';
|
import prefixStyles from '../../modules/prefixStyles';
|
||||||
|
|
||||||
const createDeclarationString = (prop, val) => {
|
const createDeclarationString = (prop, val) => {
|
||||||
const name = hyphenateStyleName(prop);
|
const name = hyphenateStyleName(prop);
|
||||||
@@ -19,6 +19,6 @@ const createDeclarationString = (prop, val) => {
|
|||||||
* // => 'color:blue;width:20px'
|
* // => 'color:blue;width:20px'
|
||||||
*/
|
*/
|
||||||
const generateCss = style =>
|
const generateCss = style =>
|
||||||
mapKeyValue(prefixAll(style), createDeclarationString).sort().join(';');
|
mapKeyValue(prefixStyles(style), createDeclarationString).sort().join(';');
|
||||||
|
|
||||||
module.exports = generateCss;
|
module.exports = generateCss;
|
||||||
|
|||||||
@@ -71,15 +71,17 @@ const i18nStyle = originalStyle => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const value = style[prop];
|
||||||
|
|
||||||
if (PROPERTIES_TO_SWAP[prop]) {
|
if (PROPERTIES_TO_SWAP[prop]) {
|
||||||
const newProp = flipProperty(prop);
|
const newProp = flipProperty(prop);
|
||||||
nextStyle[newProp] = style[prop];
|
nextStyle[newProp] = value;
|
||||||
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
|
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
|
||||||
nextStyle[prop] = swapLeftRight(style[prop]);
|
nextStyle[prop] = swapLeftRight(value);
|
||||||
} else if (prop === 'textShadowOffset') {
|
} else if (prop === 'textShadowOffset') {
|
||||||
nextStyle[prop] = style[prop];
|
nextStyle[prop] = value;
|
||||||
nextStyle[prop].width = additiveInverse(style[prop].width);
|
nextStyle[prop].width = additiveInverse(value.width);
|
||||||
} else if (prop === 'transform') {
|
} else if (prop === 'transform' && Array.isArray(value)) {
|
||||||
nextStyle[prop] = style[prop].map(flipTransform);
|
nextStyle[prop] = style[prop].map(flipTransform);
|
||||||
} else {
|
} else {
|
||||||
nextStyle[prop] = style[prop];
|
nextStyle[prop] = style[prop];
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ const convertTransformMatrix = transformMatrix => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resolveTransform = (resolvedStyle, style) => {
|
const resolveTransform = (resolvedStyle, style) => {
|
||||||
|
let transform = style.transform;
|
||||||
if (Array.isArray(style.transform)) {
|
if (Array.isArray(style.transform)) {
|
||||||
const transform = style.transform.map(mapTransform).join(' ');
|
transform = style.transform.map(mapTransform).join(' ');
|
||||||
resolvedStyle.transform = transform;
|
|
||||||
} else if (style.transformMatrix) {
|
} else if (style.transformMatrix) {
|
||||||
const transform = convertTransformMatrix(style.transformMatrix);
|
transform = convertTransformMatrix(style.transformMatrix);
|
||||||
resolvedStyle.transform = transform;
|
|
||||||
}
|
}
|
||||||
|
resolvedStyle.transform = transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = resolveTransform;
|
module.exports = resolveTransform;
|
||||||
|
|||||||
@@ -206,7 +206,8 @@ class ListView extends Component {
|
|||||||
totalIndex++;
|
totalIndex++;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
renderSeparator && (rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)
|
renderSeparator &&
|
||||||
|
(rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)
|
||||||
) {
|
) {
|
||||||
const adjacentRowHighlighted =
|
const adjacentRowHighlighted =
|
||||||
this.state.highlightedRow.sectionID === sectionID &&
|
this.state.highlightedRow.sectionID === sectionID &&
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const TextOnlyStylePropTypes = {
|
|||||||
textShadowRadius: number,
|
textShadowRadius: number,
|
||||||
writingDirection: WritingDirectionPropType,
|
writingDirection: WritingDirectionPropType,
|
||||||
/* @platform web */
|
/* @platform web */
|
||||||
|
textIndent: numberOrString,
|
||||||
textOverflow: string,
|
textOverflow: string,
|
||||||
textRendering: oneOf(['auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed']),
|
textRendering: oneOf(['auto', 'geometricPrecision', 'optimizeLegibility', 'optimizeSpeed']),
|
||||||
textTransform: oneOf(['capitalize', 'lowercase', 'none', 'uppercase']),
|
textTransform: oneOf(['capitalize', 'lowercase', 'none', 'uppercase']),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ module.exports = {
|
|||||||
* @platform unsupported
|
* @platform unsupported
|
||||||
*/
|
*/
|
||||||
elevation: number,
|
elevation: number,
|
||||||
/*
|
/**
|
||||||
* @platform web
|
* @platform web
|
||||||
*/
|
*/
|
||||||
backgroundAttachment: string,
|
backgroundAttachment: string,
|
||||||
@@ -29,7 +29,9 @@ module.exports = {
|
|||||||
backgroundRepeat: string,
|
backgroundRepeat: string,
|
||||||
backgroundSize: string,
|
backgroundSize: string,
|
||||||
boxShadow: string,
|
boxShadow: string,
|
||||||
|
clip: string,
|
||||||
cursor: string,
|
cursor: string,
|
||||||
|
filter: string,
|
||||||
outline: string,
|
outline: string,
|
||||||
outlineColor: ColorPropType,
|
outlineColor: ColorPropType,
|
||||||
perspective: oneOfType([number, string]),
|
perspective: oneOfType([number, string]),
|
||||||
@@ -40,5 +42,6 @@ module.exports = {
|
|||||||
transitionTimingFunction: string,
|
transitionTimingFunction: string,
|
||||||
userSelect: string,
|
userSelect: string,
|
||||||
willChange: string,
|
willChange: string,
|
||||||
|
WebkitMaskImage: string,
|
||||||
WebkitOverflowScrolling: oneOf(['auto', 'touch'])
|
WebkitOverflowScrolling: oneOf(['auto', 'touch'])
|
||||||
};
|
};
|
||||||
|
|||||||
97
src/index.js
97
src/index.js
@@ -1,54 +1,57 @@
|
|||||||
import createDOMElement from './modules/createDOMElement';
|
import {
|
||||||
import findNodeHandle from './modules/findNodeHandle';
|
// top-level API
|
||||||
import modality from './modules/modality';
|
findNodeHandle,
|
||||||
import NativeModules from './modules/NativeModules';
|
render,
|
||||||
import processColor from './modules/processColor';
|
unmountComponentAtNode,
|
||||||
import { render, unmountComponentAtNode } from 'react-dom';
|
|
||||||
|
|
||||||
// APIs
|
// modules
|
||||||
import Animated from './apis/Animated';
|
createDOMElement,
|
||||||
import AppRegistry from './apis/AppRegistry';
|
NativeModules,
|
||||||
import AppState from './apis/AppState';
|
processColor,
|
||||||
import AsyncStorage from './apis/AsyncStorage';
|
|
||||||
import BackAndroid from './apis/BackAndroid';
|
|
||||||
import Clipboard from './apis/Clipboard';
|
|
||||||
import Dimensions from './apis/Dimensions';
|
|
||||||
import Easing from 'animated/lib/Easing';
|
|
||||||
import I18nManager from './apis/I18nManager';
|
|
||||||
import InteractionManager from './apis/InteractionManager';
|
|
||||||
import Linking from './apis/Linking';
|
|
||||||
import NetInfo from './apis/NetInfo';
|
|
||||||
import PanResponder from './apis/PanResponder';
|
|
||||||
import PixelRatio from './apis/PixelRatio';
|
|
||||||
import Platform from './apis/Platform';
|
|
||||||
import StyleSheet from './apis/StyleSheet';
|
|
||||||
import UIManager from './apis/UIManager';
|
|
||||||
import Vibration from './apis/Vibration';
|
|
||||||
|
|
||||||
// components
|
// APIs
|
||||||
import ActivityIndicator from './components/ActivityIndicator';
|
Animated,
|
||||||
import Button from './components/Button';
|
AppRegistry,
|
||||||
import Image from './components/Image';
|
AppState,
|
||||||
import ListView from './components/ListView';
|
AsyncStorage,
|
||||||
import ProgressBar from './components/ProgressBar';
|
BackAndroid,
|
||||||
import ScrollView from './components/ScrollView';
|
Clipboard,
|
||||||
import StatusBar from './components/StatusBar';
|
Dimensions,
|
||||||
import Switch from './components/Switch';
|
Easing,
|
||||||
import Text from './components/Text';
|
I18nManager,
|
||||||
import TextInput from './components/TextInput';
|
InteractionManager,
|
||||||
import Touchable from './components/Touchable/Touchable';
|
Linking,
|
||||||
import TouchableHighlight from './components/Touchable/TouchableHighlight';
|
NetInfo,
|
||||||
import TouchableOpacity from './components/Touchable/TouchableOpacity';
|
PanResponder,
|
||||||
import TouchableWithoutFeedback from './components/Touchable/TouchableWithoutFeedback';
|
PixelRatio,
|
||||||
import View from './components/View';
|
Platform,
|
||||||
|
StyleSheet,
|
||||||
|
UIManager,
|
||||||
|
Vibration,
|
||||||
|
|
||||||
// propTypes
|
// components
|
||||||
import ColorPropType from './propTypes/ColorPropType';
|
ActivityIndicator,
|
||||||
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
|
Button,
|
||||||
import PointPropType from './propTypes/PointPropType';
|
Image,
|
||||||
import ViewPropTypes from './components/View/ViewPropTypes';
|
ListView,
|
||||||
|
ProgressBar,
|
||||||
|
ScrollView,
|
||||||
|
StatusBar,
|
||||||
|
Switch,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
Touchable,
|
||||||
|
TouchableHighlight,
|
||||||
|
TouchableOpacity,
|
||||||
|
TouchableWithoutFeedback,
|
||||||
|
View,
|
||||||
|
|
||||||
modality();
|
// propTypes
|
||||||
|
ColorPropType,
|
||||||
|
EdgeInsetsPropType,
|
||||||
|
PointPropType,
|
||||||
|
ViewPropTypes
|
||||||
|
} from './module';
|
||||||
|
|
||||||
const ReactNative = {
|
const ReactNative = {
|
||||||
// top-level API
|
// top-level API
|
||||||
|
|||||||
50
src/module.js
Normal file
50
src/module.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
export { default as createDOMElement } from './modules/createDOMElement';
|
||||||
|
export { default as findNodeHandle } from './modules/findNodeHandle';
|
||||||
|
export { default as NativeModules } from './modules/NativeModules';
|
||||||
|
export { default as processColor } from './modules/processColor';
|
||||||
|
export { render, unmountComponentAtNode } from 'react-dom';
|
||||||
|
|
||||||
|
// APIs
|
||||||
|
export { default as Animated } from './apis/Animated';
|
||||||
|
export { default as AppRegistry } from './apis/AppRegistry';
|
||||||
|
export { default as AppState } from './apis/AppState';
|
||||||
|
export { default as AsyncStorage } from './apis/AsyncStorage';
|
||||||
|
export { default as BackAndroid } from './apis/BackAndroid';
|
||||||
|
export { default as Clipboard } from './apis/Clipboard';
|
||||||
|
export { default as Dimensions } from './apis/Dimensions';
|
||||||
|
export { default as Easing } from 'animated/lib/Easing';
|
||||||
|
export { default as I18nManager } from './apis/I18nManager';
|
||||||
|
export { default as InteractionManager } from './apis/InteractionManager';
|
||||||
|
export { default as Linking } from './apis/Linking';
|
||||||
|
export { default as NetInfo } from './apis/NetInfo';
|
||||||
|
export { default as PanResponder } from './apis/PanResponder';
|
||||||
|
export { default as PixelRatio } from './apis/PixelRatio';
|
||||||
|
export { default as Platform } from './apis/Platform';
|
||||||
|
export { default as StyleSheet } from './apis/StyleSheet';
|
||||||
|
export { default as UIManager } from './apis/UIManager';
|
||||||
|
export { default as Vibration } from './apis/Vibration';
|
||||||
|
|
||||||
|
// components
|
||||||
|
export { default as ActivityIndicator } from './components/ActivityIndicator';
|
||||||
|
export { default as Button } from './components/Button';
|
||||||
|
export { default as Image } from './components/Image';
|
||||||
|
export { default as ListView } from './components/ListView';
|
||||||
|
export { default as ProgressBar } from './components/ProgressBar';
|
||||||
|
export { default as ScrollView } from './components/ScrollView';
|
||||||
|
export { default as StatusBar } from './components/StatusBar';
|
||||||
|
export { default as Switch } from './components/Switch';
|
||||||
|
export { default as Text } from './components/Text';
|
||||||
|
export { default as TextInput } from './components/TextInput';
|
||||||
|
export { default as Touchable } from './components/Touchable/Touchable';
|
||||||
|
export { default as TouchableHighlight } from './components/Touchable/TouchableHighlight';
|
||||||
|
export { default as TouchableOpacity } from './components/Touchable/TouchableOpacity';
|
||||||
|
export {
|
||||||
|
default as TouchableWithoutFeedback
|
||||||
|
} from './components/Touchable/TouchableWithoutFeedback';
|
||||||
|
export { default as View } from './components/View';
|
||||||
|
|
||||||
|
// propTypes
|
||||||
|
export { default as ColorPropType } from './propTypes/ColorPropType';
|
||||||
|
export { default as EdgeInsetsPropType } from './propTypes/EdgeInsetsPropType';
|
||||||
|
export { default as PointPropType } from './propTypes/PointPropType';
|
||||||
|
export { default as ViewPropTypes } from './components/View/ViewPropTypes';
|
||||||
@@ -67,12 +67,18 @@ const NativeMethodsMixin = {
|
|||||||
* the initial styles from the DOM node and merge them with incoming props.
|
* the initial styles from the DOM node and merge them with incoming props.
|
||||||
*/
|
*/
|
||||||
setNativeProps(nativeProps: Object) {
|
setNativeProps(nativeProps: Object) {
|
||||||
// DOM state
|
// Copy of existing DOM state
|
||||||
const node = findNodeHandle(this);
|
const node = findNodeHandle(this);
|
||||||
const classList = [...node.classList];
|
const classList = Array.prototype.slice.call(node.classList);
|
||||||
|
const style = { ...node.style };
|
||||||
|
// See #454
|
||||||
|
delete style.length;
|
||||||
|
|
||||||
|
const domStyleProps = { classList, style };
|
||||||
|
|
||||||
|
// Next DOM state
|
||||||
const domProps = createDOMProps(nativeProps, style =>
|
const domProps = createDOMProps(nativeProps, style =>
|
||||||
StyleRegistry.resolveStateful(style, classList)
|
StyleRegistry.resolveStateful(style, domStyleProps)
|
||||||
);
|
);
|
||||||
UIManager.updateView(node, domProps, this);
|
UIManager.updateView(node, domProps, this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,10 @@ const applyLayout = Component => {
|
|||||||
if (!this._isMounted) return;
|
if (!this._isMounted) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
layout.x !== x || layout.y !== y || layout.width !== width || layout.height !== height
|
layout.x !== x ||
|
||||||
|
layout.y !== y ||
|
||||||
|
layout.width !== width ||
|
||||||
|
layout.height !== height
|
||||||
) {
|
) {
|
||||||
this._layoutState = { x, y, width, height };
|
this._layoutState = { x, y, width, height };
|
||||||
const nativeEvent = { layout: this._layoutState };
|
const nativeEvent = { layout: this._layoutState };
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ import '../injectResponderEventPlugin';
|
|||||||
|
|
||||||
import AccessibilityUtil from '../AccessibilityUtil';
|
import AccessibilityUtil from '../AccessibilityUtil';
|
||||||
import createDOMProps from '../createDOMProps';
|
import createDOMProps from '../createDOMProps';
|
||||||
|
import modality from '../modality';
|
||||||
import normalizeNativeEvent from '../normalizeNativeEvent';
|
import normalizeNativeEvent from '../normalizeNativeEvent';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
modality();
|
||||||
|
|
||||||
const eventHandlerNames = {
|
const eventHandlerNames = {
|
||||||
onClick: true,
|
onClick: true,
|
||||||
onClickCapture: true,
|
onClickCapture: true,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* eslint-env jasmine, jest */
|
/* eslint-env jasmine, jest */
|
||||||
|
|
||||||
import prefixInlineStyles from '../prefixInlineStyles';
|
import { prefixInlineStyles } from '..';
|
||||||
|
|
||||||
describe('apis/StyleSheet/prefixInlineStyles', () => {
|
describe('modules/prefixStyles', () => {
|
||||||
test('handles array values', () => {
|
test('handles array values for inline styles', () => {
|
||||||
const style = {
|
const style = {
|
||||||
display: ['-webkit-flex', 'flex']
|
display: ['-webkit-flex', 'flex']
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import prefixAll from 'inline-style-prefixer/static';
|
import prefixAll from 'inline-style-prefixer/static';
|
||||||
|
|
||||||
const prefixInlineStyles = style => {
|
export default prefixAll;
|
||||||
|
|
||||||
|
export const prefixInlineStyles = style => {
|
||||||
const prefixedStyles = prefixAll(style);
|
const prefixedStyles = prefixAll(style);
|
||||||
|
|
||||||
// React@15 removed undocumented support for fallback values in
|
// React@15 removed undocumented support for fallback values in
|
||||||
@@ -14,5 +16,3 @@ const prefixInlineStyles = style => {
|
|||||||
|
|
||||||
return prefixedStyles;
|
return prefixedStyles;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = prefixInlineStyles;
|
|
||||||
@@ -14,7 +14,6 @@ const LayoutPropTypes = {
|
|||||||
]),
|
]),
|
||||||
alignItems: oneOf(['baseline', 'center', 'flex-end', 'flex-start', 'stretch']),
|
alignItems: oneOf(['baseline', 'center', 'flex-end', 'flex-start', 'stretch']),
|
||||||
alignSelf: oneOf(['auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch']),
|
alignSelf: oneOf(['auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch']),
|
||||||
aspectRatio: number,
|
|
||||||
backfaceVisibility: hiddenOrVisible,
|
backfaceVisibility: hiddenOrVisible,
|
||||||
borderWidth: numberOrString,
|
borderWidth: numberOrString,
|
||||||
borderBottomWidth: numberOrString,
|
borderBottomWidth: numberOrString,
|
||||||
@@ -61,7 +60,26 @@ const LayoutPropTypes = {
|
|||||||
top: numberOrString,
|
top: numberOrString,
|
||||||
visibility: hiddenOrVisible,
|
visibility: hiddenOrVisible,
|
||||||
width: numberOrString,
|
width: numberOrString,
|
||||||
zIndex: number
|
zIndex: number,
|
||||||
|
/**
|
||||||
|
* @platform unsupported
|
||||||
|
*/
|
||||||
|
aspectRatio: number,
|
||||||
|
/**
|
||||||
|
* @platform web
|
||||||
|
*/
|
||||||
|
gridAutoColumns: string,
|
||||||
|
gridAutoFlow: string,
|
||||||
|
gridAutoRows: string,
|
||||||
|
gridColumnEnd: string,
|
||||||
|
gridColumnGap: string,
|
||||||
|
gridColumnStart: string,
|
||||||
|
gridRowEnd: string,
|
||||||
|
gridRowGap: string,
|
||||||
|
gridRowStart: string,
|
||||||
|
gridTemplateColumns: string,
|
||||||
|
gridTemplateRows: string,
|
||||||
|
gridTemplateAreas: string
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = LayoutPropTypes;
|
module.exports = LayoutPropTypes;
|
||||||
|
|||||||
4
src/vendor/setValueForStyles/index.js
vendored
4
src/vendor/setValueForStyles/index.js
vendored
@@ -158,7 +158,9 @@ function dangerousStyleValue(name, value, component) {
|
|||||||
|
|
||||||
var isNonNumeric = isNaN(value);
|
var isNonNumeric = isNaN(value);
|
||||||
if (
|
if (
|
||||||
isNonNumeric || value === 0 || (unitlessNumbers.hasOwnProperty(name) && unitlessNumbers[name])
|
isNonNumeric ||
|
||||||
|
value === 0 ||
|
||||||
|
(unitlessNumbers.hasOwnProperty(name) && unitlessNumbers[name])
|
||||||
) {
|
) {
|
||||||
return '' + value; // cast to string
|
return '' + value; // cast to string
|
||||||
}
|
}
|
||||||
|
|||||||
30
yarn.lock
30
yarn.lock
@@ -931,9 +931,9 @@ babel-plugin-transform-react-jsx@^6.3.13, babel-plugin-transform-react-jsx@^6.5.
|
|||||||
babel-plugin-syntax-jsx "^6.8.0"
|
babel-plugin-syntax-jsx "^6.8.0"
|
||||||
babel-runtime "^6.0.0"
|
babel-runtime "^6.0.0"
|
||||||
|
|
||||||
babel-plugin-transform-react-remove-prop-types@^0.4.0:
|
babel-plugin-transform-react-remove-prop-types@^0.4.2:
|
||||||
version "0.4.0"
|
version "0.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.0.tgz#f63840e7953563d661be8c647b094d74d7363f17"
|
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.2.tgz#97e3cab4d05938df91e16c0473737ef6c575a2e6"
|
||||||
|
|
||||||
babel-plugin-transform-regenerator@6.16.1:
|
babel-plugin-transform-regenerator@6.16.1:
|
||||||
version "6.16.1"
|
version "6.16.1"
|
||||||
@@ -1917,19 +1917,13 @@ dashdash@^1.12.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
date-now@1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-1.0.1.tgz#bb7d086438debe4182a485fb3df3fbfb99d6153c"
|
|
||||||
|
|
||||||
date-now@^0.1.4:
|
date-now@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||||
|
|
||||||
debounce:
|
debounce@1.0.2:
|
||||||
version "1.0.0"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.0.tgz#0948af513d2e4ce407916f8506a423d3f9cf72d8"
|
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.2.tgz#503cc674d8d7f737099664fb75ddbd36b9626dc6"
|
||||||
dependencies:
|
|
||||||
date-now "1.0.1"
|
|
||||||
|
|
||||||
debug@2.6.1:
|
debug@2.6.1:
|
||||||
version "2.6.1"
|
version "2.6.1"
|
||||||
@@ -2330,9 +2324,9 @@ escope@^3.6.0:
|
|||||||
esrecurse "^4.1.0"
|
esrecurse "^4.1.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-config-prettier@^1.6.0:
|
eslint-config-prettier@^1.7.0:
|
||||||
version "1.6.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-1.6.0.tgz#56e53a8eb461c06eced20cec40d765c185100fd5"
|
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-1.7.0.tgz#cda3ce22df1e852daa9370f1f3446e8b8a02ce44"
|
||||||
dependencies:
|
dependencies:
|
||||||
get-stdin "^5.0.1"
|
get-stdin "^5.0.1"
|
||||||
|
|
||||||
@@ -5012,9 +5006,9 @@ preserve@^0.2.0:
|
|||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||||
|
|
||||||
prettier@^1.1.0:
|
prettier@^1.2.2:
|
||||||
version "1.1.0"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.1.0.tgz#9d6ad005703efefa66b6999b8916bfc6afeaf9f8"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.2.2.tgz#22d17c1132faaaea1f1d4faea31f19f7a1959f3e"
|
||||||
dependencies:
|
dependencies:
|
||||||
ast-types "0.9.8"
|
ast-types "0.9.8"
|
||||||
babel-code-frame "6.22.0"
|
babel-code-frame "6.22.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user