mirror of
https://github.com/zoriya/react-native-web.git
synced 2025-12-06 06:36:13 +00:00
Update prettier and reformat source code
This commit is contained in:
@@ -3,7 +3,10 @@
|
||||
const babelConfig = require('./babel.config.js');
|
||||
|
||||
module.exports = {
|
||||
coveragePathIgnorePatterns: ['/node_modules/', '<rootDir>/packages/react-native-web/src/vendor/'],
|
||||
coveragePathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'<rootDir>/packages/react-native-web/src/vendor/'
|
||||
],
|
||||
fakeTimers: {
|
||||
enableGlobally: true
|
||||
},
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
const babelConfig = require('./babel.config.js');
|
||||
|
||||
module.exports = {
|
||||
coveragePathIgnorePatterns: ['/node_modules/', '<rootDir>/packages/react-native-web/src/vendor/'],
|
||||
coveragePathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'<rootDir>/packages/react-native-web/src/vendor/'
|
||||
],
|
||||
fakeTimers: {
|
||||
enableGlobally: true
|
||||
},
|
||||
|
||||
85
package-lock.json
generated
85
package-lock.json
generated
@@ -47,7 +47,7 @@
|
||||
"lint-staged": "^10.5.4",
|
||||
"minimist": "^1.2.6",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"prettier": "^2.2.1"
|
||||
"prettier": "^2.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@11ty/dependency-tree": {
|
||||
@@ -3802,14 +3802,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz",
|
||||
"integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==",
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||
"integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"loader-utils": "^1.4.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"make-dir": "^3.1.0",
|
||||
"schema-utils": "^2.6.5"
|
||||
},
|
||||
@@ -3821,33 +3820,6 @@
|
||||
"webpack": ">=2"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader/node_modules/json5": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader/node_modules/loader-utils": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
|
||||
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader/node_modules/schema-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||
@@ -11632,16 +11604,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
|
||||
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
|
||||
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty": {
|
||||
@@ -14662,7 +14636,7 @@
|
||||
"react-native-web": "0.18.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-react-native-web": "0.18.4",
|
||||
"css-loader": "^6.7.1",
|
||||
"style-loader": "^3.3.1",
|
||||
@@ -17560,36 +17534,17 @@
|
||||
}
|
||||
},
|
||||
"babel-loader": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz",
|
||||
"integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==",
|
||||
"version": "8.2.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
|
||||
"integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"loader-utils": "^1.4.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"make-dir": "^3.1.0",
|
||||
"schema-utils": "^2.6.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
|
||||
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||
@@ -17757,7 +17712,7 @@
|
||||
"benchmarks": {
|
||||
"version": "file:packages/benchmarks",
|
||||
"requires": {
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-react-native-web": "0.18.4",
|
||||
"classnames": "^2.3.1",
|
||||
"css-loader": "^6.7.1",
|
||||
@@ -23131,9 +23086,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
|
||||
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
|
||||
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty": {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"lint-staged": "^10.5.4",
|
||||
"minimist": "^1.2.6",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"prettier": "^2.2.1"
|
||||
"prettier": "^2.7.1"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/react-native-web",
|
||||
@@ -81,7 +81,6 @@
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
},
|
||||
|
||||
@@ -4,7 +4,8 @@ const isCommonJS = (opts) => opts.commonjs === true;
|
||||
|
||||
const getDistLocation = (importName, opts) => {
|
||||
const format = isCommonJS(opts) ? 'cjs/' : '';
|
||||
const internalName = importName === 'unstable_createElement' ? 'createElement' : importName;
|
||||
const internalName =
|
||||
importName === 'unstable_createElement' ? 'createElement' : importName;
|
||||
if (internalName === 'index') {
|
||||
return `react-native-web/dist/${format}index`;
|
||||
} else if (internalName && moduleMap[internalName]) {
|
||||
@@ -24,7 +25,8 @@ const isReactNativeRequire = (t, node) => {
|
||||
t.isIdentifier(init.callee) &&
|
||||
init.callee.name === 'require' &&
|
||||
init.arguments.length === 1 &&
|
||||
(init.arguments[0].value === 'react-native' || init.arguments[0].value === 'react-native-web')
|
||||
(init.arguments[0].value === 'react-native' ||
|
||||
init.arguments[0].value === 'react-native-web')
|
||||
);
|
||||
};
|
||||
|
||||
@@ -48,7 +50,11 @@ module.exports = function ({ types: t }) {
|
||||
|
||||
if (distLocation) {
|
||||
return t.importDeclaration(
|
||||
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
|
||||
[
|
||||
t.importDefaultSpecifier(
|
||||
t.identifier(specifier.local.name)
|
||||
)
|
||||
],
|
||||
t.stringLiteral(distLocation)
|
||||
);
|
||||
}
|
||||
@@ -76,7 +82,12 @@ module.exports = function ({ types: t }) {
|
||||
if (distLocation) {
|
||||
return t.exportNamedDeclaration(
|
||||
null,
|
||||
[t.exportSpecifier(t.identifier('default'), t.identifier(exportName))],
|
||||
[
|
||||
t.exportSpecifier(
|
||||
t.identifier('default'),
|
||||
t.identifier(exportName)
|
||||
)
|
||||
],
|
||||
t.stringLiteral(distLocation)
|
||||
);
|
||||
}
|
||||
@@ -98,13 +109,18 @@ module.exports = function ({ types: t }) {
|
||||
if (t.isObjectPattern(id)) {
|
||||
const imports = id.properties
|
||||
.map((identifier) => {
|
||||
const distLocation = getDistLocation(identifier.key.name, state.opts);
|
||||
const distLocation = getDistLocation(
|
||||
identifier.key.name,
|
||||
state.opts
|
||||
);
|
||||
if (distLocation) {
|
||||
return t.variableDeclaration(path.node.kind, [
|
||||
t.variableDeclarator(
|
||||
t.identifier(identifier.value.name),
|
||||
t.memberExpression(
|
||||
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)]),
|
||||
t.callExpression(t.identifier('require'), [
|
||||
t.stringLiteral(distLocation)
|
||||
]),
|
||||
t.identifier('default')
|
||||
)
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"react-native-web": "0.18.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-react-native-web": "0.18.4",
|
||||
"css-loader": "^6.7.1",
|
||||
"style-loader": "^3.3.1",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import Benchmark from './Benchmark';
|
||||
import { Picker, StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
|
||||
import {
|
||||
Picker,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import Button from './Button';
|
||||
import { IconClear, IconEye } from './Icons';
|
||||
@@ -26,9 +32,12 @@ export default class App extends Component {
|
||||
|
||||
render() {
|
||||
const { tests } = this.props;
|
||||
const { currentBenchmarkName, status, currentLibraryName, results } = this.state;
|
||||
const currentImplementation = tests[currentBenchmarkName][currentLibraryName];
|
||||
const { Component, Provider, getComponentProps, sampleCount } = currentImplementation;
|
||||
const { currentBenchmarkName, status, currentLibraryName, results } =
|
||||
this.state;
|
||||
const currentImplementation =
|
||||
tests[currentBenchmarkName][currentLibraryName];
|
||||
const { Component, Provider, getComponentProps, sampleCount } =
|
||||
currentImplementation;
|
||||
|
||||
return (
|
||||
<Layout
|
||||
@@ -45,9 +54,15 @@ export default class App extends Component {
|
||||
selectedValue={currentLibraryName}
|
||||
style={styles.picker}
|
||||
>
|
||||
{Object.keys(tests[currentBenchmarkName]).map((libraryName) => (
|
||||
<Picker.Item key={libraryName} label={libraryName} value={libraryName} />
|
||||
))}
|
||||
{Object.keys(tests[currentBenchmarkName]).map(
|
||||
(libraryName) => (
|
||||
<Picker.Item
|
||||
key={libraryName}
|
||||
label={libraryName}
|
||||
value={libraryName}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Picker>
|
||||
</View>
|
||||
<View style={{ width: 1, backgroundColor: colors.fadedGray }} />
|
||||
@@ -185,24 +200,27 @@ export default class App extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_createHandleComplete = ({ benchmarkName, libraryName, sampleCount }) => (results) => {
|
||||
this.setState(
|
||||
(state) => ({
|
||||
results: state.results.concat([
|
||||
{
|
||||
...results,
|
||||
benchmarkName,
|
||||
libraryName,
|
||||
libraryVersion: this.props.tests[benchmarkName][libraryName].version
|
||||
}
|
||||
]),
|
||||
status: 'complete'
|
||||
}),
|
||||
this._scrollToEnd
|
||||
);
|
||||
// console.log(results);
|
||||
// console.log(results.samples.map(sample => sample.elapsed.toFixed(1)).join('\n'));
|
||||
};
|
||||
_createHandleComplete =
|
||||
({ benchmarkName, libraryName, sampleCount }) =>
|
||||
(results) => {
|
||||
this.setState(
|
||||
(state) => ({
|
||||
results: state.results.concat([
|
||||
{
|
||||
...results,
|
||||
benchmarkName,
|
||||
libraryName,
|
||||
libraryVersion:
|
||||
this.props.tests[benchmarkName][libraryName].version
|
||||
}
|
||||
]),
|
||||
status: 'complete'
|
||||
}),
|
||||
this._scrollToEnd
|
||||
);
|
||||
// console.log(results);
|
||||
// console.log(results.samples.map(sample => sample.elapsed.toFixed(1)).join('\n'));
|
||||
};
|
||||
|
||||
_handleClear = () => {
|
||||
this.setState(() => ({ results: [] }));
|
||||
|
||||
@@ -13,7 +13,11 @@ import * as Timing from './timing';
|
||||
import React, { Component } from 'react';
|
||||
import { getMean, getMedian, getStdDev } from './math';
|
||||
|
||||
import type { BenchResultsType, FullSampleTimingType, SampleTimingType } from './types';
|
||||
import type {
|
||||
BenchResultsType,
|
||||
FullSampleTimingType,
|
||||
SampleTimingType
|
||||
} from './types';
|
||||
|
||||
export const BenchmarkType = {
|
||||
MOUNT: 'mount',
|
||||
@@ -21,7 +25,10 @@ export const BenchmarkType = {
|
||||
UNMOUNT: 'unmount'
|
||||
};
|
||||
|
||||
const shouldRender = (cycle: number, type: $Values<typeof BenchmarkType>): boolean => {
|
||||
const shouldRender = (
|
||||
cycle: number,
|
||||
type: $Values<typeof BenchmarkType>
|
||||
): boolean => {
|
||||
switch (type) {
|
||||
// Render every odd iteration (first, third, etc)
|
||||
// Mounts and unmounts the component
|
||||
@@ -36,7 +43,10 @@ const shouldRender = (cycle: number, type: $Values<typeof BenchmarkType>): boole
|
||||
}
|
||||
};
|
||||
|
||||
const shouldRecord = (cycle: number, type: $Values<typeof BenchmarkType>): boolean => {
|
||||
const shouldRecord = (
|
||||
cycle: number,
|
||||
type: $Values<typeof BenchmarkType>
|
||||
): boolean => {
|
||||
switch (type) {
|
||||
// Record every odd iteration (when mounted: first, third, etc)
|
||||
case BenchmarkType.MOUNT:
|
||||
@@ -91,7 +101,10 @@ type BenchmarkStateType = {
|
||||
* Benchmark
|
||||
* TODO: documentation
|
||||
*/
|
||||
export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkStateType> {
|
||||
export default class Benchmark extends Component<
|
||||
BenchmarkPropsType,
|
||||
BenchmarkStateType
|
||||
> {
|
||||
_raf: ?Function;
|
||||
_startTime: number;
|
||||
_samples: Array<SampleTimingType>;
|
||||
@@ -125,11 +138,16 @@ export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkSt
|
||||
|
||||
componentWillReceiveProps(nextProps: BenchmarkPropsType) {
|
||||
if (nextProps) {
|
||||
this.setState((state) => ({ componentProps: nextProps.getComponentProps(state.cycle) }));
|
||||
this.setState((state) => ({
|
||||
componentProps: nextProps.getComponentProps(state.cycle)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps: BenchmarkPropsType, nextState: BenchmarkStateType) {
|
||||
componentWillUpdate(
|
||||
nextProps: BenchmarkPropsType,
|
||||
nextState: BenchmarkStateType
|
||||
) {
|
||||
if (nextState.running && !this.state.running) {
|
||||
this._startTime = Timing.now();
|
||||
}
|
||||
@@ -154,7 +172,10 @@ export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkSt
|
||||
|
||||
if (running) {
|
||||
const now = Timing.now();
|
||||
if (!isDone(cycle, sampleCount, type) && now - this._startTime < timeout) {
|
||||
if (
|
||||
!isDone(cycle, sampleCount, type) &&
|
||||
now - this._startTime < timeout
|
||||
) {
|
||||
this._handleCycleComplete();
|
||||
} else {
|
||||
this._handleComplete(now);
|
||||
@@ -174,7 +195,9 @@ export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkSt
|
||||
if (running && shouldRecord(cycle, type)) {
|
||||
this._samples[cycle] = { scriptingStart: Timing.now() };
|
||||
}
|
||||
return running && shouldRender(cycle, type) ? <Component {...componentProps} /> : null;
|
||||
return running && shouldRender(cycle, type) ? (
|
||||
<Component {...componentProps} />
|
||||
) : null;
|
||||
}
|
||||
|
||||
start() {
|
||||
@@ -209,7 +232,12 @@ export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkSt
|
||||
return this._samples.reduce(
|
||||
(
|
||||
memo: Array<FullSampleTimingType>,
|
||||
{ scriptingStart, scriptingEnd, layoutStart, layoutEnd }: SampleTimingType
|
||||
{
|
||||
scriptingStart,
|
||||
scriptingEnd,
|
||||
layoutStart,
|
||||
layoutEnd
|
||||
}: SampleTimingType
|
||||
): Array<FullSampleTimingType> => {
|
||||
memo.push({
|
||||
start: scriptingStart,
|
||||
@@ -232,12 +260,16 @@ export default class Benchmark extends Component<BenchmarkPropsType, BenchmarkSt
|
||||
this.setState(() => ({ running: false, cycle: 0 }));
|
||||
|
||||
const runTime = endTime - this._startTime;
|
||||
const sortedElapsedTimes = samples.map(({ start, end }) => end - start).sort(sortNumbers);
|
||||
const sortedElapsedTimes = samples
|
||||
.map(({ start, end }) => end - start)
|
||||
.sort(sortNumbers);
|
||||
const sortedScriptingElapsedTimes = samples
|
||||
.map(({ scriptingStart, scriptingEnd }) => scriptingEnd - scriptingStart)
|
||||
.sort(sortNumbers);
|
||||
const sortedLayoutElapsedTimes = samples
|
||||
.map(({ layoutStart, layoutEnd }) => (layoutEnd || 0) - (layoutStart || 0))
|
||||
.map(
|
||||
({ layoutStart, layoutEnd }) => (layoutEnd || 0) - (layoutStart || 0)
|
||||
)
|
||||
.sort(sortNumbers);
|
||||
|
||||
onComplete({
|
||||
|
||||
@@ -23,5 +23,7 @@ export const getMedian = (values: ValuesType): number => {
|
||||
}
|
||||
|
||||
const numbers = values.sort((a: number, b: number) => a - b);
|
||||
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
|
||||
return (
|
||||
(numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2
|
||||
);
|
||||
};
|
||||
|
||||
@@ -30,7 +30,9 @@ export default class Button extends Component<*> {
|
||||
]}
|
||||
testID={testID}
|
||||
>
|
||||
<Text style={[styles.text, textStyle, disabled && styles.textDisabled]}>{title}</Text>
|
||||
<Text style={[styles.text, textStyle, disabled && styles.textDisabled]}>
|
||||
{title}
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { unstable_createElement as createElement, StyleSheet } from 'react-native';
|
||||
import {
|
||||
unstable_createElement as createElement,
|
||||
StyleSheet
|
||||
} from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
|
||||
@@ -11,8 +11,13 @@ export default class Layout extends Component {
|
||||
const { viewPanel, actionPanel, listPanel } = this.props;
|
||||
const { widescreen } = this.state;
|
||||
return (
|
||||
<View onLayout={this._handleLayout} style={[styles.root, widescreen && styles.row]}>
|
||||
<View style={[widescreen ? styles.grow : styles.stackPanel, styles.layer]}>
|
||||
<View
|
||||
onLayout={this._handleLayout}
|
||||
style={[styles.root, widescreen && styles.row]}
|
||||
>
|
||||
<View
|
||||
style={[widescreen ? styles.grow : styles.stackPanel, styles.layer]}
|
||||
>
|
||||
{viewPanel}
|
||||
</View>
|
||||
<View style={styles.grow}>
|
||||
|
||||
@@ -13,7 +13,9 @@ class AppText extends React.Component {
|
||||
render() {
|
||||
const { style, ...rest } = this.props;
|
||||
const { isInAParentText } = this.context;
|
||||
return <Text {...rest} style={[!isInAParentText && styles.baseText, style]} />;
|
||||
return (
|
||||
<Text {...rest} style={[!isInAParentText && styles.baseText, style]} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ const baseUnit = 1.3125;
|
||||
const { canUseDOM } = ExecutionEnvironment;
|
||||
|
||||
const createPlatformLength = (multiplier) =>
|
||||
Platform.select({ web: `${multiplier}rem`, default: multiplier * baseFontSize });
|
||||
Platform.select({
|
||||
web: `${multiplier}rem`,
|
||||
default: multiplier * baseFontSize
|
||||
});
|
||||
|
||||
/**
|
||||
* Exported variables
|
||||
@@ -52,8 +55,7 @@ export const colors = {
|
||||
export const fontFamilies = {
|
||||
normal: 'System',
|
||||
japan: Platform.select({
|
||||
web:
|
||||
'Arial, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka, "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif',
|
||||
web: 'Arial, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka, "メイリオ", Meiryo, "MS Pゴシック", "MS PGothic", sans-serif',
|
||||
default: 'System'
|
||||
}),
|
||||
rtl: Platform.select({ web: 'Tahoma, Arial, sans-serif', default: 'System' })
|
||||
@@ -89,7 +91,8 @@ if (Platform.OS === 'web' && canUseDOM) {
|
||||
const { medium, large } = breakpoints;
|
||||
const htmlElement = document.documentElement;
|
||||
const setFontSize = (width) => {
|
||||
const fontSize = width > medium ? (width > large ? '18px' : '17px') : '16px';
|
||||
const fontSize =
|
||||
width > medium ? (width > large ? '18px' : '17px') : '16px';
|
||||
if (htmlElement) {
|
||||
htmlElement.style.fontSize = fontSize;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { BenchmarkType } from '../app/Benchmark';
|
||||
import React from 'react';
|
||||
import { interpolatePurples, interpolateBuPu, interpolateRdPu } from 'd3-scale-chromatic';
|
||||
import {
|
||||
interpolatePurples,
|
||||
interpolateBuPu,
|
||||
interpolateRdPu
|
||||
} from 'd3-scale-chromatic';
|
||||
|
||||
const targetSize = 10;
|
||||
|
||||
@@ -37,7 +41,12 @@ class SierpinskiTriangle extends React.Component {
|
||||
// introduce randomness to ensure that repeated runs don't produce the same colors
|
||||
const color = fn((renderCount * Math.random()) / 20);
|
||||
return (
|
||||
<Dot color={color} size={targetSize} x={x - targetSize / 2} y={y - targetSize / 2} />
|
||||
<Dot
|
||||
color={color}
|
||||
size={targetSize}
|
||||
x={x - targetSize / 2}
|
||||
y={y - targetSize / 2}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,7 +81,9 @@ class SierpinskiTriangle extends React.Component {
|
||||
</React.Fragment>
|
||||
);
|
||||
} else {
|
||||
return <span style={{ color: 'white' }}>No implementation available</span>;
|
||||
return (
|
||||
<span style={{ color: 'white' }}>No implementation available</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,13 @@ import React from 'react';
|
||||
import View from './View';
|
||||
import styles from './box-styles.css';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({
|
||||
color,
|
||||
fixed = false,
|
||||
layout = 'column',
|
||||
outer = false,
|
||||
...other
|
||||
}) => (
|
||||
<View
|
||||
{...other}
|
||||
className={classnames(styles[`color${color}`], {
|
||||
|
||||
@@ -5,7 +5,9 @@ import styles from './view-styles.css';
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const props = this.props;
|
||||
return <div {...props} className={classnames(styles.initial, props.className)} />;
|
||||
return (
|
||||
<div {...props} className={classnames(styles.initial, props.className)} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({
|
||||
color,
|
||||
fixed = false,
|
||||
layout = 'column',
|
||||
outer = false,
|
||||
...other
|
||||
}) => (
|
||||
<View
|
||||
{...other}
|
||||
style={{
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({
|
||||
color,
|
||||
fixed = false,
|
||||
layout = 'column',
|
||||
outer = false,
|
||||
...other
|
||||
}) => (
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { unstable_createElement as createElement, StyleSheet } from 'react-native';
|
||||
import {
|
||||
unstable_createElement as createElement,
|
||||
StyleSheet
|
||||
} from 'react-native';
|
||||
|
||||
const Dot = ({ size, x, y, children, color }) =>
|
||||
createElement('div', {
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import React from 'react';
|
||||
import View from './View';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({
|
||||
color,
|
||||
fixed = false,
|
||||
layout = 'column',
|
||||
outer = false,
|
||||
...other
|
||||
}) => (
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
|
||||
@@ -2,7 +2,13 @@ import React from 'react';
|
||||
import View from './View';
|
||||
import { StyleSheet } from 'react-native-web';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({
|
||||
color,
|
||||
fixed = false,
|
||||
layout = 'column',
|
||||
outer = false,
|
||||
...other
|
||||
}) => (
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
|
||||
@@ -12,7 +12,13 @@ const packageNames = Object.keys(implementations);
|
||||
const createTestBlock = (fn) => {
|
||||
return packageNames.reduce((testSetups, packageName) => {
|
||||
const { name, components, version } = implementations[packageName];
|
||||
const { Component, getComponentProps, sampleCount, Provider, benchmarkType } = fn(components);
|
||||
const {
|
||||
Component,
|
||||
getComponentProps,
|
||||
sampleCount,
|
||||
Provider,
|
||||
benchmarkType
|
||||
} = fn(components);
|
||||
|
||||
testSetups[packageName] = {
|
||||
Component,
|
||||
@@ -31,14 +37,26 @@ const tests = {
|
||||
'Mount deep tree': createTestBlock((components) => ({
|
||||
benchmarkType: 'mount',
|
||||
Component: Tree,
|
||||
getComponentProps: () => ({ breadth: 2, components, depth: 7, id: 0, wrap: 1 }),
|
||||
getComponentProps: () => ({
|
||||
breadth: 2,
|
||||
components,
|
||||
depth: 7,
|
||||
id: 0,
|
||||
wrap: 1
|
||||
}),
|
||||
Provider: components.Provider,
|
||||
sampleCount: 50
|
||||
})),
|
||||
'Mount wide tree': createTestBlock((components) => ({
|
||||
benchmarkType: 'mount',
|
||||
Component: Tree,
|
||||
getComponentProps: () => ({ breadth: 6, components, depth: 3, id: 0, wrap: 2 }),
|
||||
getComponentProps: () => ({
|
||||
breadth: 6,
|
||||
components,
|
||||
depth: 3,
|
||||
id: 0,
|
||||
wrap: 2
|
||||
}),
|
||||
Provider: components.Provider,
|
||||
sampleCount: 50
|
||||
})),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const BundleAnalyzerPlugin =
|
||||
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const path = require('path');
|
||||
|
||||
const appDirectory = path.resolve(__dirname);
|
||||
|
||||
@@ -158,7 +158,9 @@ export function contextmenu(target, defaultPayload = {}) {
|
||||
}
|
||||
dispatch(domEvents.mousedown({ ...payload, ctrlKey }));
|
||||
if (platform.get() === 'mac') {
|
||||
dispatch(domEvents.contextmenu({ button, buttons, ctrlKey, preventDefault }));
|
||||
dispatch(
|
||||
domEvents.contextmenu({ button, buttons, ctrlKey, preventDefault })
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const button = buttonType.secondary;
|
||||
@@ -167,7 +169,9 @@ export function contextmenu(target, defaultPayload = {}) {
|
||||
dispatch(domEvents.pointerdown({ ...payload, button, buttons }));
|
||||
}
|
||||
dispatch(domEvents.mousedown({ ...payload, button, buttons }));
|
||||
dispatch(domEvents.contextmenu({ ...payload, button, buttons, preventDefault }));
|
||||
dispatch(
|
||||
domEvents.contextmenu({ ...payload, button, buttons, preventDefault })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,7 +327,9 @@ export function pointermove(target, defaultPayload) {
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
if (hasPointerEvent()) {
|
||||
dispatch(domEvents.pointermove({ pressure: 0.5, button: -1, ...payload }));
|
||||
dispatch(
|
||||
domEvents.pointermove({ pressure: 0.5, button: -1, ...payload })
|
||||
);
|
||||
}
|
||||
dispatch(domEvents.mousemove(payload));
|
||||
} else {
|
||||
@@ -354,7 +360,8 @@ export function pointerup(target, defaultPayload) {
|
||||
};
|
||||
|
||||
const isPrimaryButton = payload.button === buttonType.primary;
|
||||
const isContextMenuAction = platform.get() === 'mac' && payload.ctrlKey === true;
|
||||
const isContextMenuAction =
|
||||
platform.get() === 'mac' && payload.ctrlKey === true;
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
if (hasPointerEvent()) {
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
'use strict';
|
||||
|
||||
import createEvent from './createEvent';
|
||||
import { buttonType, buttonsType, defaultPointerSize, defaultBrowserChromeSize } from './constants';
|
||||
import {
|
||||
buttonType,
|
||||
buttonsType,
|
||||
defaultPointerSize,
|
||||
defaultBrowserChromeSize
|
||||
} from './constants';
|
||||
|
||||
/**
|
||||
* Native event object mocks for higher-level events.
|
||||
@@ -299,9 +304,13 @@ export function lostpointercapture(payload) {
|
||||
export function mousedown(payload) {
|
||||
// The value of 'button' and 'buttons' for 'mousedown' must not be none.
|
||||
const button =
|
||||
payload != null && payload.button !== buttonType.none ? payload.button : buttonType.primary;
|
||||
payload != null && payload.button !== buttonType.none
|
||||
? payload.button
|
||||
: buttonType.primary;
|
||||
const buttons =
|
||||
payload != null && payload.buttons !== buttonsType.none ? payload.buttons : buttonsType.primary;
|
||||
payload != null && payload.buttons !== buttonsType.none
|
||||
? payload.buttons
|
||||
: buttonsType.primary;
|
||||
|
||||
return createMouseEvent('mousedown', {
|
||||
...payload,
|
||||
|
||||
@@ -24,7 +24,9 @@ export function describeWithPointerEvent(message, describeFn) {
|
||||
}
|
||||
|
||||
export function testWithPointerType(message, testFn) {
|
||||
const table = hasPointerEvent() ? ['mouse', 'touch', 'pen'] : ['mouse', 'touch'];
|
||||
const table = hasPointerEvent()
|
||||
? ['mouse', 'touch', 'pen']
|
||||
: ['mouse', 'touch'];
|
||||
test.each(table)(`${message}: %s`, (pointerType) => {
|
||||
testFn(pointerType);
|
||||
});
|
||||
|
||||
@@ -34,7 +34,9 @@ function markdownitTagToClass(md, mapping = {}) {
|
||||
}
|
||||
});
|
||||
}
|
||||
md.core.ruler.push('markdownit-tag-to-class', (state) => parseTokens(state.tokens));
|
||||
md.core.ruler.push('markdownit-tag-to-class', (state) =>
|
||||
parseTokens(state.tokens)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = function (eleventyConfig) {
|
||||
|
||||
@@ -29,7 +29,11 @@ function setupNavigationDrawer() {
|
||||
navopen = false;
|
||||
}
|
||||
document.addEventListener('click', (e) => {
|
||||
if (navopen && !navigation.contains(e.target) && !showbtn.contains(e.target)) {
|
||||
if (
|
||||
navopen &&
|
||||
!navigation.contains(e.target) &&
|
||||
!showbtn.contains(e.target)
|
||||
) {
|
||||
closeNavigation();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,8 +18,16 @@ export default function ActivityIndicatorPage() {
|
||||
<Example title="ActivityIndicator">
|
||||
<View style={styles.row}>
|
||||
<ActivityIndicator style={styles.item} />
|
||||
<ActivityIndicator animating={false} hidesWhenStopped={false} style={styles.item} />
|
||||
<ActivityIndicator animating={animating} hidesWhenStopped={false} style={styles.item} />
|
||||
<ActivityIndicator
|
||||
animating={false}
|
||||
hidesWhenStopped={false}
|
||||
style={styles.item}
|
||||
/>
|
||||
<ActivityIndicator
|
||||
animating={animating}
|
||||
hidesWhenStopped={false}
|
||||
style={styles.item}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<ActivityIndicator color="#1DA1F2" size="small" style={styles.item} />
|
||||
|
||||
@@ -27,7 +27,8 @@ export default function AppStatePage() {
|
||||
return (
|
||||
<Example title="AppState">
|
||||
<Text style={{ marginTop: '1rem' }}>
|
||||
AppState.currentState: <Text style={{ fontWeight: 'bold' }}>{state.currentState}</Text>
|
||||
AppState.currentState:{' '}
|
||||
<Text style={{ fontWeight: 'bold' }}>{state.currentState}</Text>
|
||||
</Text>
|
||||
<Text>Active count: {state.active}</Text>
|
||||
<Text>Background count: {state.background}</Text>
|
||||
|
||||
@@ -44,7 +44,11 @@ export default function CheckboxPage() {
|
||||
<CheckBox color="#E0245E" value={true} />
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<CheckBox color="#1DA1F2" style={{ height: 32, width: 32 }} value={checked} />
|
||||
<CheckBox
|
||||
color="#1DA1F2"
|
||||
style={{ height: 32, width: 32 }}
|
||||
value={checked}
|
||||
/>
|
||||
</View>
|
||||
</Example>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,9 @@ import Example from '../../shared/example';
|
||||
|
||||
export default function ClipboardPage() {
|
||||
const setString = () => {
|
||||
const success = Clipboard.setString('This text was copied to the clipboard by React Native');
|
||||
const success = Clipboard.setString(
|
||||
'This text was copied to the clipboard by React Native'
|
||||
);
|
||||
console.log(`Clipboard.setString success? ${success}`);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export default function DimensionsPage() {
|
||||
<Text style={{ marginVertical: '1em' }} suppressHydrationWarnings={true}>
|
||||
window: {JSON.stringify(windowDims, null, 2)}
|
||||
</Text>
|
||||
<Text suppressHydrationWarnings={true}>screen: {JSON.stringify(screenDims, null, 2)}</Text>
|
||||
<Text suppressHydrationWarnings={true}>
|
||||
screen: {JSON.stringify(screenDims, null, 2)}
|
||||
</Text>
|
||||
</Example>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ import { StyleSheet } from 'react-native';
|
||||
import Example from '../../shared/example';
|
||||
import { FlatList, Text, TouchableOpacity, View } from 'react-native-web';
|
||||
|
||||
const multiSelectData = ['First', 'Second', 'Third'].map((title, id) => ({ id, title }));
|
||||
const multiSelectData = ['First', 'Second', 'Third'].map((title, id) => ({
|
||||
id,
|
||||
title
|
||||
}));
|
||||
const minimalData = ['a', 'b', 'c', 'd', 'e'].map((key) => ({ key }));
|
||||
const pageExamplesData = ['minimal', 'multiSelect'].map((type) => ({ type }));
|
||||
|
||||
@@ -17,7 +20,9 @@ class MyListItem extends React.PureComponent {
|
||||
return (
|
||||
<TouchableOpacity onPress={this._onPress}>
|
||||
<View>
|
||||
<Text style={[styles.listItemText, { color: textColor }]}>{this.props.title}</Text>
|
||||
<Text style={[styles.listItemText, { color: textColor }]}>
|
||||
{this.props.title}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
@@ -70,7 +75,9 @@ function renderExampleItem({ item }) {
|
||||
<Text style={styles.exampleHeaderText}>Minimal FlatList:</Text>
|
||||
<FlatList
|
||||
data={minimalData}
|
||||
renderItem={({ item }) => <Text style={styles.listItemText}>{item.key}</Text>}
|
||||
renderItem={({ item }) => (
|
||||
<Text style={styles.listItemText}>{item.key}</Text>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -93,10 +100,14 @@ export default function FlatListPage() {
|
||||
<Example title="FlatList">
|
||||
<FlatList
|
||||
ListFooterComponent={
|
||||
<Text style={styles.allExamplesFooter}>(Example ListFooterComponent Here)</Text>
|
||||
<Text style={styles.allExamplesFooter}>
|
||||
(Example ListFooterComponent Here)
|
||||
</Text>
|
||||
}
|
||||
ListHeaderComponent={
|
||||
<Text style={styles.allExamplesHeader}>(Example ListHeaderComponent Here)</Text>
|
||||
<Text style={styles.allExamplesHeader}>
|
||||
(Example ListHeaderComponent Here)
|
||||
</Text>
|
||||
}
|
||||
data={pageExamplesData}
|
||||
renderItem={renderExampleItem}
|
||||
|
||||
@@ -80,22 +80,38 @@ export default function ImagePage() {
|
||||
<View style={styles.row}>
|
||||
<View style={styles.column}>
|
||||
<Text style={[styles.text]}>Center</Text>
|
||||
<Image resizeMode="center" source={resizesource} style={styles.resizeMode} />
|
||||
<Image
|
||||
resizeMode="center"
|
||||
source={resizesource}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={[styles.text]}>Contain</Text>
|
||||
<Image resizeMode="contain" source={resizesource} style={styles.resizeMode} />
|
||||
<Image
|
||||
resizeMode="contain"
|
||||
source={resizesource}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Divider />
|
||||
<View style={styles.row}>
|
||||
<View style={styles.column}>
|
||||
<Text style={[styles.text]}>Cover</Text>
|
||||
<Image resizeMode="cover" source={resizesource} style={styles.resizeMode} />
|
||||
<Image
|
||||
resizeMode="cover"
|
||||
source={resizesource}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={[styles.text]}>Stretch</Text>
|
||||
<Image resizeMode="stretch" source={resizesource} style={styles.resizeMode} />
|
||||
<Image
|
||||
resizeMode="stretch"
|
||||
source={resizesource}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Example>
|
||||
|
||||
@@ -30,8 +30,10 @@ export default function IndexPage() {
|
||||
<Text style={styles.title}>React Native for Web</Text>
|
||||
</View>
|
||||
<Text style={styles.text}>
|
||||
<Link href="https://github.com/necolas/react-native-web">React Native for Web</Link> example
|
||||
app built on Next.js
|
||||
<Link href="https://github.com/necolas/react-native-web">
|
||||
React Native for Web
|
||||
</Link>{' '}
|
||||
example app built on Next.js
|
||||
</Text>
|
||||
|
||||
<View accessibilityRole="list">
|
||||
|
||||
@@ -22,7 +22,13 @@ import {
|
||||
} from 'react-native';
|
||||
import Example from '../../shared/example';
|
||||
|
||||
type Item = { title: string, text: string, key: string, pressed: boolean, noImage?: ?boolean };
|
||||
type Item = {
|
||||
title: string,
|
||||
text: string,
|
||||
key: string,
|
||||
pressed: boolean,
|
||||
noImage?: ?boolean
|
||||
};
|
||||
|
||||
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
|
||||
|
||||
@@ -103,7 +109,10 @@ class ItemComponent extends React.PureComponent<{
|
||||
]}
|
||||
>
|
||||
{!item.noImage && <Image source={imgSource} style={styles.thumb} />}
|
||||
<Text numberOfLines={horizontal || fixedHeight ? 3 : undefined} style={styles.text}>
|
||||
<Text
|
||||
numberOfLines={horizontal || fixedHeight ? 3 : undefined}
|
||||
style={styles.text}
|
||||
>
|
||||
{item.title} - {item.text}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -147,7 +156,10 @@ class SeparatorComponent extends React.PureComponent<{}> {
|
||||
class ItemSeparatorComponent extends React.PureComponent<{}> {
|
||||
render() {
|
||||
const style = this.props.highlighted
|
||||
? [styles.itemSeparator, { marginLeft: 0, backgroundColor: 'rgb(217, 217, 217)' }]
|
||||
? [
|
||||
styles.itemSeparator,
|
||||
{ marginLeft: 0, backgroundColor: 'rgb(217, 217, 217)' }
|
||||
]
|
||||
: styles.itemSeparator;
|
||||
return <View style={style} />;
|
||||
}
|
||||
@@ -251,16 +263,24 @@ class SingleColumnExample extends React.PureComponent {
|
||||
};
|
||||
|
||||
_onChangeScrollToIndex = (text) => {
|
||||
this._listRef.getNode().scrollToIndex({ viewPosition: 0.5, index: Number(text) });
|
||||
this._listRef
|
||||
.getNode()
|
||||
.scrollToIndex({ viewPosition: 0.5, index: Number(text) });
|
||||
};
|
||||
|
||||
_scrollPos = new Animated.Value(0);
|
||||
_scrollSinkX = Animated.event([{ nativeEvent: { contentOffset: { x: this._scrollPos } } }], {
|
||||
useNativeDriver: true
|
||||
});
|
||||
_scrollSinkY = Animated.event([{ nativeEvent: { contentOffset: { y: this._scrollPos } } }], {
|
||||
useNativeDriver: true
|
||||
});
|
||||
_scrollSinkX = Animated.event(
|
||||
[{ nativeEvent: { contentOffset: { x: this._scrollPos } } }],
|
||||
{
|
||||
useNativeDriver: true
|
||||
}
|
||||
);
|
||||
_scrollSinkY = Animated.event(
|
||||
[{ nativeEvent: { contentOffset: { y: this._scrollPos } } }],
|
||||
{
|
||||
useNativeDriver: true
|
||||
}
|
||||
);
|
||||
|
||||
componentDidUpdate() {
|
||||
this._listRef.getNode().recordInteraction(); // e.g. flipping logViewable switch
|
||||
@@ -268,7 +288,8 @@ class SingleColumnExample extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const filterRegex = new RegExp(String(this.state.filterText), 'i');
|
||||
const filter = (item) => filterRegex.test(item.text) || filterRegex.test(item.title);
|
||||
const filter = (item) =>
|
||||
filterRegex.test(item.text) || filterRegex.test(item.title);
|
||||
const filteredData = this.state.data.filter(filter);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -279,7 +300,10 @@ class SingleColumnExample extends React.PureComponent {
|
||||
placeholder="Search..."
|
||||
value={this.state.filterText}
|
||||
/>
|
||||
<PlainInput onChangeText={this._onChangeScrollToIndex} placeholder="scrollToIndex..." />
|
||||
<PlainInput
|
||||
onChangeText={this._onChangeScrollToIndex}
|
||||
placeholder="scrollToIndex..."
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.options}>
|
||||
{renderSmallSwitchOption(this, 'virtualized')}
|
||||
@@ -300,17 +324,24 @@ class SingleColumnExample extends React.PureComponent {
|
||||
data={filteredData}
|
||||
debug={this.state.debug}
|
||||
disableVirtualization={!this.state.virtualized}
|
||||
getItemLayout={this.state.fixedHeight ? this._getItemLayout : undefined}
|
||||
getItemLayout={
|
||||
this.state.fixedHeight ? this._getItemLayout : undefined
|
||||
}
|
||||
horizontal={this.state.horizontal}
|
||||
inverted={this.state.inverted}
|
||||
key={(this.state.horizontal ? 'h' : 'v') + (this.state.fixedHeight ? 'f' : 'd')}
|
||||
key={
|
||||
(this.state.horizontal ? 'h' : 'v') +
|
||||
(this.state.fixedHeight ? 'f' : 'd')
|
||||
}
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardShouldPersistTaps="always"
|
||||
legacyImplementation={false}
|
||||
numColumns={1}
|
||||
onEndReached={this._onEndReached}
|
||||
onRefresh={this._onRefresh}
|
||||
onScroll={this.state.horizontal ? this._scrollSinkX : this._scrollSinkY}
|
||||
onScroll={
|
||||
this.state.horizontal ? this._scrollSinkX : this._scrollSinkY
|
||||
}
|
||||
onViewableItemsChanged={this._onViewableItemsChanged}
|
||||
ref={this._captureRef}
|
||||
refreshing={false}
|
||||
|
||||
@@ -309,7 +309,9 @@ const BorderRadiiExample = withRTLState(({ isRTL, setRTL }) => {
|
||||
function Block(props) {
|
||||
let description;
|
||||
if (props.description) {
|
||||
description = <Text style={blockStyles.descriptionText}>{props.description}</Text>;
|
||||
description = (
|
||||
<Text style={blockStyles.descriptionText}>{props.description}</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -379,13 +381,19 @@ class LayoutRTLExample extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView dir={this.state.isRTL ? 'rtl' : 'ltr'} style={[styles.container]}>
|
||||
<ScrollView
|
||||
dir={this.state.isRTL ? 'rtl' : 'ltr'}
|
||||
style={[styles.container]}
|
||||
>
|
||||
<Block title={'Current layout direction'}>
|
||||
<View dir="ltr" style={styles.directionBox}>
|
||||
<Text style={styles.directionText}>
|
||||
{this.state.isRTL ? 'Right-to-Left' : 'Left-to-Right'}
|
||||
</Text>
|
||||
<Switch onValueChange={this._onDirectionChange} value={this.state.isRTL} />
|
||||
<Switch
|
||||
onValueChange={this._onDirectionChange}
|
||||
value={this.state.isRTL}
|
||||
/>
|
||||
</View>
|
||||
</Block>
|
||||
|
||||
@@ -419,13 +427,22 @@ class LayoutRTLExample extends React.Component {
|
||||
|
||||
<Block title={'A simple list-item layout'}>
|
||||
<View style={styles.list}>
|
||||
<ListItem imageSource={{ uri: 'https://picsum.photos/130/130?image=222' }} />
|
||||
<ListItem imageSource={{ uri: 'https://picsum.photos/130/130?image=250' }} />
|
||||
<ListItem
|
||||
imageSource={{ uri: 'https://picsum.photos/130/130?image=222' }}
|
||||
/>
|
||||
<ListItem
|
||||
imageSource={{ uri: 'https://picsum.photos/130/130?image=250' }}
|
||||
/>
|
||||
</View>
|
||||
</Block>
|
||||
|
||||
<Block title={'Working with icons'}>
|
||||
<View style={[styles.flexDirectionRow, { justifyContent: 'space-around' }]}>
|
||||
<View
|
||||
style={[
|
||||
styles.flexDirectionRow,
|
||||
{ justifyContent: 'space-around' }
|
||||
]}
|
||||
>
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Image source={iconSource} style={styles.image} />
|
||||
<Text style={styles.fontSizeSmall}>No RTL flip</Text>
|
||||
@@ -433,7 +450,10 @@ class LayoutRTLExample extends React.Component {
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Image
|
||||
source={iconSource}
|
||||
style={[styles.image, { transform: [{ scaleX: this.state.isRTL ? -1 : 1 }] }]}
|
||||
style={[
|
||||
styles.image,
|
||||
{ transform: [{ scaleX: this.state.isRTL ? -1 : 1 }] }
|
||||
]}
|
||||
/>
|
||||
<Text style={styles.fontSizeSmall}>RTL flip</Text>
|
||||
</View>
|
||||
|
||||
@@ -11,7 +11,10 @@ function AnimatedModal({ animationType }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onPress={() => setIsVisible(true)} title={`Animation '${animationType}'`} />
|
||||
<Button
|
||||
onPress={() => setIsVisible(true)}
|
||||
title={`Animation '${animationType}'`}
|
||||
/>
|
||||
<Modal
|
||||
animationType={animationType}
|
||||
onRequestClose={() => setIsVisible(false)}
|
||||
@@ -54,13 +57,21 @@ function Modalception({ depth = 1 }) {
|
||||
return (
|
||||
<>
|
||||
<Button onPress={() => setIsVisible(true)} title={'Open modal'} />
|
||||
<Modal onRequestClose={() => setIsVisible(false)} transparent visible={isVisible}>
|
||||
<Modal
|
||||
onRequestClose={() => setIsVisible(false)}
|
||||
transparent
|
||||
visible={isVisible}
|
||||
>
|
||||
<View style={[styles.containeralt, offset]}>
|
||||
<Text>This is in Modal {depth}</Text>
|
||||
<Gap />
|
||||
{isVisible ? <Modalception depth={depth + 1} /> : null}
|
||||
<Gap />
|
||||
<Button color="red" onPress={() => setIsVisible(false)} title={'Close'} />
|
||||
<Button
|
||||
color="red"
|
||||
onPress={() => setIsVisible(false)}
|
||||
title={'Close'}
|
||||
/>
|
||||
</View>
|
||||
</Modal>
|
||||
</>
|
||||
@@ -90,9 +101,15 @@ function TransparentModal() {
|
||||
return (
|
||||
<>
|
||||
<Button onPress={() => setIsVisible(true)} title={'Transparent modal'} />
|
||||
<Modal onRequestClose={() => setIsVisible(false)} transparent visible={isVisible}>
|
||||
<Modal
|
||||
onRequestClose={() => setIsVisible(false)}
|
||||
transparent
|
||||
visible={isVisible}
|
||||
>
|
||||
<View style={styles.containeralt}>
|
||||
<Text style={{ textAlign: 'center' }}>Modal with "transparent" value</Text>
|
||||
<Text style={{ textAlign: 'center' }}>
|
||||
Modal with "transparent" value
|
||||
</Text>
|
||||
<Gap />
|
||||
<Button onPress={() => setIsVisible(false)} title={'Close'} />
|
||||
</View>
|
||||
|
||||
@@ -42,7 +42,11 @@ class DraggableCircle extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View ref={this._setCircleRef} style={styles.circle} {...this._panResponder.panHandlers} />
|
||||
<View
|
||||
ref={this._setCircleRef}
|
||||
style={styles.circle}
|
||||
{...this._panResponder.panHandlers}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -65,12 +69,18 @@ class DraggableCircle extends React.PureComponent {
|
||||
this.circle && this.circle.setNativeProps(this._circleStyles);
|
||||
}
|
||||
|
||||
_handleStartShouldSetPanResponder = (e: Object, gestureState: Object): boolean => {
|
||||
_handleStartShouldSetPanResponder = (
|
||||
e: Object,
|
||||
gestureState: Object
|
||||
): boolean => {
|
||||
// Should we become active when the user presses down on the circle?
|
||||
return true;
|
||||
};
|
||||
|
||||
_handleMoveShouldSetPanResponder = (e: Object, gestureState: Object): boolean => {
|
||||
_handleMoveShouldSetPanResponder = (
|
||||
e: Object,
|
||||
gestureState: Object
|
||||
): boolean => {
|
||||
// Should we become active when the user moves a touch over the circle?
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Button, ScrollView, StyleSheet, View, Text, Pressable } from 'react-native';
|
||||
import {
|
||||
Button,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
Pressable
|
||||
} from 'react-native';
|
||||
import Example from '../../shared/example';
|
||||
|
||||
export default function PressablePage() {
|
||||
|
||||
@@ -23,9 +23,17 @@ export default function ProgressBarPage() {
|
||||
<Divider />
|
||||
<ProgressBar color="#E0245E" progress={1} />
|
||||
<Divider />
|
||||
<ProgressBar color="rgb(23, 191, 99)" progress={0.1} trackColor="rgba(23, 191, 99, 0.3)" />
|
||||
<ProgressBar
|
||||
color="rgb(23, 191, 99)"
|
||||
progress={0.1}
|
||||
trackColor="rgba(23, 191, 99, 0.3)"
|
||||
/>
|
||||
<Divider />
|
||||
<ProgressBar color="rgb(244, 93, 34)" progress={0.2} trackColor="rgba(244, 93, 34, 0.3)" />
|
||||
<ProgressBar
|
||||
color="rgb(244, 93, 34)"
|
||||
progress={0.2}
|
||||
trackColor="rgba(244, 93, 34, 0.3)"
|
||||
/>
|
||||
<Divider />
|
||||
<ProgressBar
|
||||
color="rgb(121, 75, 196)"
|
||||
@@ -33,7 +41,12 @@ export default function ProgressBarPage() {
|
||||
trackColor="rgba(121, 75, 196, 0.3)"
|
||||
/>
|
||||
<Divider />
|
||||
<ProgressBar color="#1DA1F2" progress={0.33} style={styles.custom} trackColor="#D1E3F6" />
|
||||
<ProgressBar
|
||||
color="#1DA1F2"
|
||||
progress={0.33}
|
||||
style={styles.custom}
|
||||
trackColor="#D1E3F6"
|
||||
/>
|
||||
</View>
|
||||
</Example>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Button, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import {
|
||||
Button,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import Example from '../../shared/example';
|
||||
|
||||
const ITEMS = [...Array(12)].map((_, i) => `Item ${i}`);
|
||||
|
||||
@@ -29,14 +29,21 @@ function renderItem({ item }) {
|
||||
function renderSectionHeader({ section }) {
|
||||
const extraStyle = { backgroundColor: section.color };
|
||||
return (
|
||||
<Text key={`sh_${section.key}`} style={[styles.sectionHeaderText, extraStyle]}>
|
||||
<Text
|
||||
key={`sh_${section.key}`}
|
||||
style={[styles.sectionHeaderText, extraStyle]}
|
||||
>
|
||||
{section.title}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
function renderSectionFooter({ section }) {
|
||||
const footerStyle = { height: 10, backgroundColor: section.color, marginBottom: 10 };
|
||||
const footerStyle = {
|
||||
height: 10,
|
||||
backgroundColor: section.color,
|
||||
marginBottom: 10
|
||||
};
|
||||
return <View key={`sf_${section.key}`} style={footerStyle} />;
|
||||
}
|
||||
|
||||
@@ -45,10 +52,14 @@ export default function SectionListPage() {
|
||||
<Example title="SectionList">
|
||||
<SectionList
|
||||
ListFooterComponent={
|
||||
<Text style={styles.examplesFooter}>(Example ListFooterComponent Here)</Text>
|
||||
<Text style={styles.examplesFooter}>
|
||||
(Example ListFooterComponent Here)
|
||||
</Text>
|
||||
}
|
||||
ListHeaderComponent={
|
||||
<Text style={styles.examplesHeader}>(Example ListHeaderComponent Here)</Text>
|
||||
<Text style={styles.examplesHeader}>
|
||||
(Example ListHeaderComponent Here)
|
||||
</Text>
|
||||
}
|
||||
renderItem={renderItem}
|
||||
renderSectionFooter={renderSectionFooter}
|
||||
|
||||
@@ -25,13 +25,31 @@ export default function SwitchPage() {
|
||||
<Divider />
|
||||
<Switch disabled={true} value={true} />
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#E0245E" disabled={true} value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#E0245E"
|
||||
disabled={true}
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch disabled={true} thumbColor="#fff" trackColor="#E0245E" value={false} />
|
||||
<Switch
|
||||
disabled={true}
|
||||
thumbColor="#fff"
|
||||
trackColor="#E0245E"
|
||||
value={false}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch disabled={true} trackColor={{ true: '#E0245E', false: '#1DA1F2' }} value={false} />
|
||||
<Switch
|
||||
disabled={true}
|
||||
trackColor={{ true: '#E0245E', false: '#1DA1F2' }}
|
||||
value={false}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch disabled={true} trackColor={{ true: '#E0245E', false: '#1DA1F2' }} value={true} />
|
||||
<Switch
|
||||
disabled={true}
|
||||
trackColor={{ true: '#E0245E', false: '#1DA1F2' }}
|
||||
value={true}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Switch value={false} />
|
||||
@@ -39,30 +57,78 @@ export default function SwitchPage() {
|
||||
<Switch value={true} />
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Switch activeThumbColor="#1DA1F2" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#1DA1F2"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#17BF63" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#17BF63"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#FFAD1F" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#FFAD1F"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#F45D22" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#F45D22"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#794BC4" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#794BC4"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#E0245E" activeTrackColor="#ccc" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#E0245E"
|
||||
activeTrackColor="#ccc"
|
||||
value={true}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#1DA1F2" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#1DA1F2"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#17BF63" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#17BF63"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#FFAD1F" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#FFAD1F"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#F45D22" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#F45D22"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#794BC4" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#794BC4"
|
||||
value={true}
|
||||
/>
|
||||
<Divider />
|
||||
<Switch activeThumbColor="#fff" activeTrackColor="#E0245E" value={true} />
|
||||
<Switch
|
||||
activeThumbColor="#fff"
|
||||
activeTrackColor="#E0245E"
|
||||
value={true}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Switch activeTrackColor="#ccc" thumbColor="#1DA1F2" value={false} />
|
||||
@@ -92,7 +158,11 @@ export default function SwitchPage() {
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<Switch style={{ height: 32, width: 32 }} thumbColor="#1DA1F2" value={checked} />
|
||||
<Switch
|
||||
style={{ height: 32, width: 32 }}
|
||||
thumbColor="#1DA1F2"
|
||||
value={checked}
|
||||
/>
|
||||
</View>
|
||||
</Example>
|
||||
);
|
||||
|
||||
@@ -33,14 +33,26 @@ export default function TextInputPage() {
|
||||
ref={nextFocus}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput defaultValue="disabled" disabled={true} style={styles.textinput} />
|
||||
<TextInput defaultValue="editable (false)" editable={false} style={styles.textinput} />
|
||||
<TextInput
|
||||
defaultValue="disabled"
|
||||
disabled={true}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
defaultValue="editable (false)"
|
||||
editable={false}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
keyboardType="numeric"
|
||||
placeholder="keyboardType 'numeric'"
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput maxLength={5} placeholder="maxLength" style={styles.textinput} />
|
||||
<TextInput
|
||||
maxLength={5}
|
||||
placeholder="maxLength"
|
||||
style={styles.textinput}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
placeholder="placeholderTextColor"
|
||||
@@ -52,7 +64,11 @@ export default function TextInputPage() {
|
||||
selectTextOnFocus={true}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput defaultValue="secureTextEntry" secureTextEntry={true} style={styles.textinput} />
|
||||
<TextInput
|
||||
defaultValue="secureTextEntry"
|
||||
secureTextEntry={true}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
multiline={true}
|
||||
numberOfLines={3}
|
||||
|
||||
@@ -36,7 +36,9 @@ function FontFamily() {
|
||||
Cochin bold
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Helvetica' }}>Helvetica</Text>
|
||||
<Text style={{ fontFamily: 'Helvetica', fontWeight: 'bold' }}>Helvetica bold</Text>
|
||||
<Text style={{ fontFamily: 'Helvetica', fontWeight: 'bold' }}>
|
||||
Helvetica bold
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Verdana' }}>Verdana</Text>
|
||||
<Text
|
||||
style={{
|
||||
@@ -107,11 +109,21 @@ function FontWeight() {
|
||||
return (
|
||||
<View>
|
||||
<Heading>fontWeight</Heading>
|
||||
<Text style={{ fontSize: 20, fontWeight: '100' }}>Move fast and be ultralight</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '200' }}>Move fast and be light</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'normal' }}>Move fast and be normal</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>Move fast and be bold</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '900' }}>Move fast and be ultrabold</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '100' }}>
|
||||
Move fast and be ultralight
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '200' }}>
|
||||
Move fast and be light
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'normal' }}>
|
||||
Move fast and be normal
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>
|
||||
Move fast and be bold
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '900' }}>
|
||||
Move fast and be ultrabold
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -124,12 +136,23 @@ function LetterSpacing() {
|
||||
<Text style={{ letterSpacing: 2, marginTop: 5 }}>letterSpacing = 2</Text>
|
||||
<Text style={{ letterSpacing: 9, marginTop: 5 }}>letterSpacing = 9</Text>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<Text style={{ fontSize: 12, letterSpacing: 2, backgroundColor: 'fuchsia', marginTop: 5 }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
letterSpacing: 2,
|
||||
backgroundColor: 'fuchsia',
|
||||
marginTop: 5
|
||||
}}
|
||||
>
|
||||
With size and background color
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={{ letterSpacing: -1, marginTop: 5 }}>letterSpacing = -1</Text>
|
||||
<Text style={{ letterSpacing: 3, backgroundColor: '#dddddd', marginTop: 5 }}>
|
||||
<Text style={{ letterSpacing: -1, marginTop: 5 }}>
|
||||
letterSpacing = -1
|
||||
</Text>
|
||||
<Text
|
||||
style={{ letterSpacing: 3, backgroundColor: '#dddddd', marginTop: 5 }}
|
||||
>
|
||||
[letterSpacing = 3]
|
||||
<Text style={{ letterSpacing: 0, backgroundColor: '#bbbbbb' }}>
|
||||
[Nested letterSpacing = 0]
|
||||
@@ -147,9 +170,9 @@ function LineHeight() {
|
||||
<View>
|
||||
<Heading>lineHeight</Heading>
|
||||
<Text style={{ lineHeight: 35 }}>
|
||||
A lot of space should display between the lines of this long passage as they wrap across
|
||||
several lines. A lot of space should display between the lines of this long passage as they
|
||||
wrap across several lines.
|
||||
A lot of space should display between the lines of this long passage as
|
||||
they wrap across several lines. A lot of space should display between
|
||||
the lines of this long passage as they wrap across several lines.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
@@ -166,18 +189,21 @@ function TextAlign() {
|
||||
'RTL'}
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'left' }}>
|
||||
left left left left left left left left left left left left left left left
|
||||
left left left left left left left left left left left left left left
|
||||
left
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'center' }}>
|
||||
center center center center center center center center center center center
|
||||
center center center center center center center center center center
|
||||
center
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'right' }}>
|
||||
right right right right right right right right right right right right right
|
||||
right right right right right right right right right right right right
|
||||
right
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'justify' }}>
|
||||
justify: this text component{"'"}s contents are laid out with "textAlign: justify" and as
|
||||
you can see all of the lines except the last one span the available width of the parent
|
||||
container.
|
||||
justify: this text component{"'"}s contents are laid out with
|
||||
"textAlign: justify" and as you can see all of the lines except the last
|
||||
one span the available width of the parent container.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
@@ -306,8 +332,9 @@ export default function TextPage() {
|
||||
<Example title="Text">
|
||||
<View style={{ maxWidth: 500 }}>
|
||||
<Text>
|
||||
Text wraps across multiple lines by default. Text wraps across multiple lines by default.
|
||||
Text wraps across multiple lines by default. Text wraps across multiple lines by default.
|
||||
Text wraps across multiple lines by default. Text wraps across
|
||||
multiple lines by default. Text wraps across multiple lines by
|
||||
default. Text wraps across multiple lines by default.
|
||||
</Text>
|
||||
|
||||
<Spacer />
|
||||
@@ -351,8 +378,10 @@ export default function TextPage() {
|
||||
|
||||
<Text>
|
||||
This text contains an inline blue view{' '}
|
||||
<View style={{ width: 25, height: 25, backgroundColor: 'steelblue' }} /> and an inline
|
||||
image{' '}
|
||||
<View
|
||||
style={{ width: 25, height: 25, backgroundColor: 'steelblue' }}
|
||||
/>{' '}
|
||||
and an inline image{' '}
|
||||
<Image
|
||||
source={{ uri: 'http://lorempixel.com/30/11' }}
|
||||
style={{ width: 30, height: 11, resizeMode: 'cover' }}
|
||||
@@ -365,8 +394,12 @@ export default function TextPage() {
|
||||
<Text>
|
||||
This text contains a view{' '}
|
||||
<View style={{ borderColor: 'red', borderWidth: 1 }}>
|
||||
<Text style={{ borderColor: 'blue', borderWidth: 1 }}>which contains</Text>
|
||||
<Text style={{ borderColor: 'green', borderWidth: 1 }}>another text.</Text>
|
||||
<Text style={{ borderColor: 'blue', borderWidth: 1 }}>
|
||||
which contains
|
||||
</Text>
|
||||
<Text style={{ borderColor: 'green', borderWidth: 1 }}>
|
||||
another text.
|
||||
</Text>
|
||||
<Text style={{ borderColor: 'yellow', borderWidth: 1 }}>
|
||||
And contains another view
|
||||
<View style={{ borderColor: 'red', borderWidth: 1 }}>
|
||||
@@ -380,10 +413,12 @@ export default function TextPage() {
|
||||
</Text>
|
||||
|
||||
<Text selectable={true}>
|
||||
This text is <Text style={{ fontWeight: 'bold' }}>selectable</Text> if you click-and-hold.
|
||||
This text is <Text style={{ fontWeight: 'bold' }}>selectable</Text> if
|
||||
you click-and-hold.
|
||||
</Text>
|
||||
<Text selectable={false}>
|
||||
This text is <Text style={{ fontWeight: 'bold' }}>not selectable</Text> if you
|
||||
This text is{' '}
|
||||
<Text style={{ fontWeight: 'bold' }}>not selectable</Text> if you
|
||||
click-and-hold.
|
||||
</Text>
|
||||
|
||||
@@ -421,7 +456,9 @@ export default function TextPage() {
|
||||
</LineExample>
|
||||
|
||||
<LineExample description="With very long word, text is limited to 1 line and long word is truncated.">
|
||||
<Text numberOfLines={1}>goal aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</Text>
|
||||
<Text numberOfLines={1}>
|
||||
goal aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
</Text>
|
||||
</LineExample>
|
||||
|
||||
<LineExample description="With space characters within adjacent truncated lines">
|
||||
|
||||
@@ -16,7 +16,10 @@ function Box({ pointerEvents }) {
|
||||
pointerEvents={pointerEvents}
|
||||
style={({ pressed }) => [styles.box, pressed && styles.purple]}
|
||||
>
|
||||
<Pressable onPress={log} style={({ pressed }) => [styles.content, pressed && styles.orange]}>
|
||||
<Pressable
|
||||
onPress={log}
|
||||
style={({ pressed }) => [styles.content, pressed && styles.orange]}
|
||||
>
|
||||
<Text>{pointerEvents}</Text>
|
||||
</Pressable>
|
||||
</Pressable>
|
||||
|
||||
@@ -23,7 +23,9 @@ const prefersReducedMotionMedia =
|
||||
|
||||
function isReduceMotionEnabled(): Promise<*> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(prefersReducedMotionMedia ? prefersReducedMotionMedia.matches : true);
|
||||
resolve(
|
||||
prefersReducedMotionMedia ? prefersReducedMotionMedia.matches : true
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,18 @@ import { render } from '@testing-library/react';
|
||||
describe('components/ActivityIndicator', () => {
|
||||
describe('prop "accessibilityLabel"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<ActivityIndicator accessibilityLabel="accessibility label" />);
|
||||
const { container } = render(
|
||||
<ActivityIndicator accessibilityLabel="accessibility label" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "accessibilityLiveRegion"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<ActivityIndicator accessibilityLiveRegion="polite" />);
|
||||
const { container } = render(
|
||||
<ActivityIndicator accessibilityLiveRegion="polite" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -46,14 +50,18 @@ describe('components/ActivityIndicator', () => {
|
||||
|
||||
describe('prop "dataSet"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<ActivityIndicator dataSet={{ one: 'one', two: 'two' }} />);
|
||||
const { container } = render(
|
||||
<ActivityIndicator dataSet={{ one: 'one', two: 'two' }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "hidesWhenStopped"', () => {
|
||||
test('is "true"', () => {
|
||||
const { container } = render(<ActivityIndicator animating={false} hidesWhenStopped={true} />);
|
||||
const { container } = render(
|
||||
<ActivityIndicator animating={false} hidesWhenStopped={true} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -126,7 +134,9 @@ describe('components/ActivityIndicator', () => {
|
||||
|
||||
describe('prop "style"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<ActivityIndicator style={{ borderWidth: 5 }} />);
|
||||
const { container } = render(
|
||||
<ActivityIndicator style={{ borderWidth: 5 }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,7 +65,9 @@ const ActivityIndicator: React.AbstractComponent<
|
||||
<View
|
||||
children={svg}
|
||||
style={[
|
||||
typeof size === 'number' ? { height: size, width: size } : indicatorSizes[size],
|
||||
typeof size === 'number'
|
||||
? { height: size, width: size }
|
||||
: indicatorSizes[size],
|
||||
styles.animation,
|
||||
!animating && styles.animationPause,
|
||||
!animating && hidesWhenStopped && styles.hidesWhenStopped
|
||||
|
||||
@@ -25,7 +25,12 @@ export default function AppContainer(props: Props): React.Node {
|
||||
const { children, WrapperComponent } = props;
|
||||
|
||||
let innerView = (
|
||||
<View children={children} key={1} pointerEvents="box-none" style={styles.appContainer} />
|
||||
<View
|
||||
children={children}
|
||||
key={1}
|
||||
pointerEvents="box-none"
|
||||
style={styles.appContainer}
|
||||
/>
|
||||
);
|
||||
|
||||
if (WrapperComponent) {
|
||||
|
||||
@@ -27,7 +27,11 @@ describe('AppRegistry', () => {
|
||||
test('callback after render', () => {
|
||||
const callback = jest.fn();
|
||||
AppRegistry.registerComponent('App', () => NoopComponent);
|
||||
AppRegistry.runApplication('App', { initialProps: {}, rootTag, callback });
|
||||
AppRegistry.runApplication('App', {
|
||||
initialProps: {},
|
||||
rootTag,
|
||||
callback
|
||||
});
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -45,14 +49,19 @@ describe('AppRegistry', () => {
|
||||
|
||||
// Run in iframe
|
||||
AppRegistry.registerComponent('App', () => NoopComponent);
|
||||
AppRegistry.runApplication('App', { initialProps: {}, rootTag: iframeRootTag });
|
||||
AppRegistry.runApplication('App', {
|
||||
initialProps: {},
|
||||
rootTag: iframeRootTag
|
||||
});
|
||||
|
||||
const iframedoc = iframeRootTag.ownerDocument;
|
||||
expect(iframedoc).toBe(iframe.contentWindow.document);
|
||||
expect(iframedoc).not.toBe(document);
|
||||
|
||||
const cssText = Array.prototype.slice
|
||||
.call(iframedoc.getElementById('react-native-stylesheet').sheet.cssRules)
|
||||
.call(
|
||||
iframedoc.getElementById('react-native-stylesheet').sheet.cssRules
|
||||
)
|
||||
.map((cssRule) => cssRule.cssText);
|
||||
|
||||
expect(cssText).toMatchInlineSnapshot(`
|
||||
|
||||
@@ -22,8 +22,13 @@ describe('AppRegistry', () => {
|
||||
|
||||
test('returns "element" and "getStyleElement"', () => {
|
||||
AppRegistry.registerComponent('App', () => NoopComponent);
|
||||
const { element, getStyleElement } = AppRegistry.getApplication('App', {});
|
||||
const styleElement = ReactDOMServer.renderToStaticMarkup(getStyleElement());
|
||||
const { element, getStyleElement } = AppRegistry.getApplication(
|
||||
'App',
|
||||
{}
|
||||
);
|
||||
const styleElement = ReactDOMServer.renderToStaticMarkup(
|
||||
getStyleElement()
|
||||
);
|
||||
|
||||
expect(element).toMatchInlineSnapshot(`
|
||||
<AppContainer
|
||||
@@ -102,9 +107,15 @@ describe('AppRegistry', () => {
|
||||
`);
|
||||
|
||||
// Second render "AlternativeComponent"
|
||||
const styles = StyleSheet.create({ root: { borderWidth: 1234, backgroundColor: 'purple' } });
|
||||
const AlternativeComponent = () => React.createElement(View, { style: styles.root });
|
||||
AppRegistry.registerComponent('AlternativeApp', () => AlternativeComponent);
|
||||
const styles = StyleSheet.create({
|
||||
root: { borderWidth: 1234, backgroundColor: 'purple' }
|
||||
});
|
||||
const AlternativeComponent = () =>
|
||||
React.createElement(View, { style: styles.root });
|
||||
AppRegistry.registerComponent(
|
||||
'AlternativeApp',
|
||||
() => AlternativeComponent
|
||||
);
|
||||
const second = getApplicationStyles('AlternativeApp');
|
||||
expect(second).toMatchInlineSnapshot(`
|
||||
"[stylesheet-group=\\"0\\"]{}
|
||||
|
||||
@@ -16,7 +16,10 @@ import renderApplication, { getApplication } from './renderApplication';
|
||||
|
||||
type AppParams = Object;
|
||||
type Runnable = {|
|
||||
getApplication?: (AppParams) => {| element: Node, getStyleElement: (any) => Node |},
|
||||
getApplication?: (AppParams) => {|
|
||||
element: Node,
|
||||
getStyleElement: (any) => Node
|
||||
|},
|
||||
run: (AppParams) => any
|
||||
|};
|
||||
|
||||
@@ -36,9 +39,8 @@ export type AppConfig = {
|
||||
const emptyObject = {};
|
||||
const runnables: {| [appKey: string]: Runnable |} = {};
|
||||
|
||||
let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook = (
|
||||
component: ComponentProvider
|
||||
) => component();
|
||||
let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook =
|
||||
(component: ComponentProvider) => component();
|
||||
let wrapperComponentProvider: ?WrapperComponentProvider;
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,10 @@ export default class AppRegistry {
|
||||
return runnables[appKey].getApplication(appParameters);
|
||||
}
|
||||
|
||||
static registerComponent(appKey: string, componentProvider: ComponentProvider): string {
|
||||
static registerComponent(
|
||||
appKey: string,
|
||||
componentProvider: ComponentProvider
|
||||
): string {
|
||||
runnables[appKey] = {
|
||||
getApplication: (appParameters) =>
|
||||
getApplication(
|
||||
@@ -103,7 +108,8 @@ export default class AppRegistry {
|
||||
}
|
||||
|
||||
static runApplication(appKey: string, appParameters: Object): void {
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
|
||||
const isDevelopment =
|
||||
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test';
|
||||
if (isDevelopment) {
|
||||
const params = { ...appParameters };
|
||||
params.rootTag = `#${params.rootTag.id}`;
|
||||
@@ -125,7 +131,9 @@ export default class AppRegistry {
|
||||
runnables[appKey].run(appParameters);
|
||||
}
|
||||
|
||||
static setComponentProviderInstrumentationHook(hook: ComponentProviderInstrumentationHook) {
|
||||
static setComponentProviderInstrumentationHook(
|
||||
hook: ComponentProviderInstrumentationHook
|
||||
) {
|
||||
componentProviderInstrumentationHook = hook;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,11 @@ export function getApplication(
|
||||
const getStyleElement = (props) => {
|
||||
const sheet = StyleSheet.getSheet();
|
||||
return (
|
||||
<style {...props} dangerouslySetInnerHTML={{ __html: sheet.textContent }} id={sheet.id} />
|
||||
<style
|
||||
{...props}
|
||||
dangerouslySetInnerHTML={{ __html: sheet.textContent }}
|
||||
id={sheet.id}
|
||||
/>
|
||||
);
|
||||
};
|
||||
return { element, getStyleElement };
|
||||
|
||||
@@ -13,7 +13,9 @@ describe('apis/AppState', () => {
|
||||
describe('addEventListener', () => {
|
||||
test('throws if the provided "eventType" is not supported', () => {
|
||||
expect(() => AppState.addEventListener('foo', handler)).toThrow();
|
||||
expect(() => AppState.addEventListener('change', handler).remove()).not.toThrow();
|
||||
expect(() =>
|
||||
AppState.addEventListener('change', handler).remove()
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
test('returns remove subscription', () => {
|
||||
|
||||
@@ -15,11 +15,17 @@ const { canUseDOM } = ExecutionEnvironment;
|
||||
|
||||
// Android 4.4 browser
|
||||
const isPrefixed =
|
||||
canUseDOM && !document.hasOwnProperty('hidden') && document.hasOwnProperty('webkitHidden');
|
||||
canUseDOM &&
|
||||
!document.hasOwnProperty('hidden') &&
|
||||
document.hasOwnProperty('webkitHidden');
|
||||
|
||||
const EVENT_TYPES = ['change', 'memoryWarning'];
|
||||
const VISIBILITY_CHANGE_EVENT = isPrefixed ? 'webkitvisibilitychange' : 'visibilitychange';
|
||||
const VISIBILITY_STATE_PROPERTY = isPrefixed ? 'webkitVisibilityState' : 'visibilityState';
|
||||
const VISIBILITY_CHANGE_EVENT = isPrefixed
|
||||
? 'webkitvisibilitychange'
|
||||
: 'visibilitychange';
|
||||
const VISIBILITY_STATE_PROPERTY = isPrefixed
|
||||
? 'webkitVisibilityState'
|
||||
: 'visibilityState';
|
||||
|
||||
const AppStates = {
|
||||
BACKGROUND: 'background',
|
||||
|
||||
@@ -27,7 +27,10 @@ function getQuery(): MediaQueryList | null {
|
||||
}
|
||||
|
||||
const query = getQuery();
|
||||
const listenerMapping = new WeakMap<AppearanceListener, DOMAppearanceListener>();
|
||||
const listenerMapping = new WeakMap<
|
||||
AppearanceListener,
|
||||
DOMAppearanceListener
|
||||
>();
|
||||
|
||||
const Appearance = {
|
||||
getColorScheme(): ColorSchemeName {
|
||||
|
||||
@@ -6,7 +6,9 @@ import { render } from '@testing-library/react';
|
||||
|
||||
describe('components/Button', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const { container } = render(<Button accessibilityLabel="accessibility label" title="" />);
|
||||
const { container } = render(
|
||||
<Button accessibilityLabel="accessibility label" title="" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ const Button: React.AbstractComponent<
|
||||
]}
|
||||
testID={testID}
|
||||
>
|
||||
<Text style={[styles.text, disabled && styles.textDisabled]}>{title}</Text>
|
||||
<Text style={[styles.text, disabled && styles.textDisabled]}>
|
||||
{title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,9 @@ function findCheckbox(container) {
|
||||
describe('CheckBox', () => {
|
||||
describe('prop "accessibilityLabel"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<CheckBox accessibilityLabel="accessibility label" />);
|
||||
const { container } = render(
|
||||
<CheckBox accessibilityLabel="accessibility label" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -32,7 +34,9 @@ describe('CheckBox', () => {
|
||||
|
||||
describe('prop "dataSet"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<CheckBox dataSet={{ one: 'one', two: 'two' }} />);
|
||||
const { container } = render(
|
||||
<CheckBox dataSet={{ one: 'one', two: 'two' }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -76,7 +80,9 @@ describe('CheckBox', () => {
|
||||
describe('prop "onChange"', () => {
|
||||
test('is called with the event object', () => {
|
||||
const onChange = jest.fn();
|
||||
const { container } = render(<CheckBox onChange={onChange} value={false} />);
|
||||
const { container } = render(
|
||||
<CheckBox onChange={onChange} value={false} />
|
||||
);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
@@ -101,7 +107,9 @@ describe('CheckBox', () => {
|
||||
describe('prop "onValueChange"', () => {
|
||||
test('when value is "false" it receives "true"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const { container } = render(<CheckBox onValueChange={onValueChange} value={false} />);
|
||||
const { container } = render(
|
||||
<CheckBox onValueChange={onValueChange} value={false} />
|
||||
);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onValueChange).toHaveBeenCalledWith(true);
|
||||
@@ -109,7 +117,9 @@ describe('CheckBox', () => {
|
||||
|
||||
test('when value is "true" it receives "false"', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const { container } = render(<CheckBox onValueChange={onValueChange} value />);
|
||||
const { container } = render(
|
||||
<CheckBox onValueChange={onValueChange} value />
|
||||
);
|
||||
const checkbox = findCheckbox(container);
|
||||
checkbox.click(); // Needed to get ReactDOM to trigger 'change' event
|
||||
expect(onValueChange).toHaveBeenCalledWith(false);
|
||||
|
||||
@@ -29,7 +29,8 @@ const CheckBox: React.AbstractComponent<
|
||||
CheckBoxProps,
|
||||
React.ElementRef<typeof View>
|
||||
> = React.forwardRef((props, forwardedRef) => {
|
||||
const { color, disabled, onChange, onValueChange, style, value, ...other } = props;
|
||||
const { color, disabled, onChange, onValueChange, style, value, ...other } =
|
||||
props;
|
||||
|
||||
function handleChange(event: Object) {
|
||||
const value = event.nativeEvent.target.checked;
|
||||
|
||||
@@ -118,7 +118,9 @@ export default class Dimensions {
|
||||
handler: (DimensionsValue) => void
|
||||
): void {
|
||||
if (Array.isArray(listeners[type])) {
|
||||
listeners[type] = listeners[type].filter((_handler) => _handler !== handler);
|
||||
listeners[type] = listeners[type].filter(
|
||||
(_handler) => _handler !== handler
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,14 +30,19 @@ describe('components/Image', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const { container } = render(
|
||||
<Image accessibilityLabel="accessibilityLabel" defaultSource={defaultSource} />
|
||||
<Image
|
||||
accessibilityLabel="accessibilityLabel"
|
||||
defaultSource={defaultSource}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('prop "blurRadius"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const { container } = render(<Image blurRadius={5} defaultSource={defaultSource} />);
|
||||
const { container } = render(
|
||||
<Image blurRadius={5} defaultSource={defaultSource} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -72,7 +77,10 @@ describe('components/Image', () => {
|
||||
width: 20
|
||||
};
|
||||
const { container } = render(
|
||||
<Image defaultSource={defaultSource} style={{ height: 20, width: 40 }} />
|
||||
<Image
|
||||
defaultSource={defaultSource}
|
||||
style={{ height: 20, width: 40 }}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
@@ -80,7 +88,9 @@ describe('components/Image', () => {
|
||||
|
||||
test('prop "draggable"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const { container } = render(<Image defaultSource={defaultSource} draggable={true} />);
|
||||
const { container } = render(
|
||||
<Image defaultSource={defaultSource} draggable={true} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -218,17 +228,25 @@ describe('components/Image', () => {
|
||||
});
|
||||
|
||||
describe('prop "resizeMode"', () => {
|
||||
['contain', 'cover', 'none', 'repeat', 'stretch', undefined].forEach((resizeMode) => {
|
||||
test(`value "${resizeMode}"`, () => {
|
||||
const { container } = render(<Image resizeMode={resizeMode} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
['contain', 'cover', 'none', 'repeat', 'stretch', undefined].forEach(
|
||||
(resizeMode) => {
|
||||
test(`value "${resizeMode}"`, () => {
|
||||
const { container } = render(<Image resizeMode={resizeMode} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('prop "source"', () => {
|
||||
test('does not throw', () => {
|
||||
const sources = [null, '', {}, { uri: '' }, { uri: 'https://google.com' }];
|
||||
const sources = [
|
||||
null,
|
||||
'',
|
||||
{},
|
||||
{ uri: '' },
|
||||
{ uri: 'https://google.com' }
|
||||
];
|
||||
sources.forEach((source) => {
|
||||
expect(() => render(<Image source={source} />)).not.toThrow();
|
||||
});
|
||||
@@ -243,12 +261,16 @@ describe('components/Image', () => {
|
||||
|
||||
test('is set immediately if the image was preloaded', () => {
|
||||
const uri = 'https://yahoo.com/favicon.ico';
|
||||
ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
onLoad();
|
||||
});
|
||||
ImageLoader.load = jest
|
||||
.fn()
|
||||
.mockImplementationOnce((_, onLoad, onError) => {
|
||||
onLoad();
|
||||
});
|
||||
return Image.prefetch(uri).then(() => {
|
||||
const source = { uri };
|
||||
const { container } = render(<Image source={source} />, { disableLifecycleMethods: true });
|
||||
const { container } = render(<Image source={source} />, {
|
||||
disableLifecycleMethods: true
|
||||
});
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
ImageUriCache.remove(uri);
|
||||
});
|
||||
@@ -261,7 +283,9 @@ describe('components/Image', () => {
|
||||
ImageUriCache.add(uriTwo);
|
||||
|
||||
// initial render
|
||||
const { container, rerender } = render(<Image source={{ uri: uriOne }} />);
|
||||
const { container, rerender } = render(
|
||||
<Image source={{ uri: uriOne }} />
|
||||
);
|
||||
ImageUriCache.remove(uriOne);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
// props update
|
||||
@@ -285,10 +309,14 @@ describe('components/Image', () => {
|
||||
const defaultUri = 'https://testing.com/preview.jpg';
|
||||
const uri = 'https://testing.com/fullSize.jpg';
|
||||
let loadCallback;
|
||||
ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
loadCallback = onLoad;
|
||||
});
|
||||
const { container } = render(<Image defaultSource={{ uri: defaultUri }} source={{ uri }} />);
|
||||
ImageLoader.load = jest
|
||||
.fn()
|
||||
.mockImplementationOnce((_, onLoad, onError) => {
|
||||
loadCallback = onLoad;
|
||||
});
|
||||
const { container } = render(
|
||||
<Image defaultSource={{ uri: defaultUri }} source={{ uri }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
loadCallback();
|
||||
@@ -306,13 +334,17 @@ describe('components/Image', () => {
|
||||
|
||||
PixelRatio.get = jest.fn(() => 1.0);
|
||||
let { container } = render(<Image source={1} />);
|
||||
expect(container.querySelector('img').src).toBe('http://localhost/static/img.png');
|
||||
expect(container.querySelector('img').src).toBe(
|
||||
'http://localhost/static/img.png'
|
||||
);
|
||||
|
||||
act(() => {
|
||||
PixelRatio.get = jest.fn(() => 2.2);
|
||||
({ container } = render(<Image source={1} />));
|
||||
});
|
||||
expect(container.querySelector('img').src).toBe('http://localhost/static/img@2x.png');
|
||||
expect(container.querySelector('img').src).toBe(
|
||||
'http://localhost/static/img@2x.png'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -324,7 +356,9 @@ describe('components/Image', () => {
|
||||
|
||||
test('supports "shadow" properties (convert to filter)', () => {
|
||||
const { container } = render(
|
||||
<Image style={{ shadowColor: 'red', shadowOffset: { width: 1, height: 1 } }} />
|
||||
<Image
|
||||
style={{ shadowColor: 'red', shadowOffset: { width: 1, height: 1 } }}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
@@ -338,7 +372,9 @@ describe('components/Image', () => {
|
||||
});
|
||||
|
||||
test('removes other unsupported View styles', () => {
|
||||
const { container } = render(<Image style={{ overlayColor: 'red', tintColor: 'blue' }} />);
|
||||
const { container } = render(
|
||||
<Image style={{ overlayColor: 'red', tintColor: 'blue' }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
353
packages/react-native-web/src/exports/Image/index.js
vendored
353
packages/react-native-web/src/exports/Image/index.js
vendored
@@ -32,7 +32,14 @@ const svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/;
|
||||
|
||||
function createTintColorSVG(tintColor, id) {
|
||||
return tintColor && id != null ? (
|
||||
<svg style={{ position: 'absolute', height: 0, visibility: 'hidden', width: 0 }}>
|
||||
<svg
|
||||
style={{
|
||||
position: 'absolute',
|
||||
height: 0,
|
||||
visibility: 'hidden',
|
||||
width: 0
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<filter id={`tint-${id}`} suppressHydrationWarning={true}>
|
||||
<feFlood floodColor={`${tintColor}`} key={tintColor} />
|
||||
@@ -91,7 +98,11 @@ function resolveAssetDimensions(source) {
|
||||
if (typeof source === 'number') {
|
||||
const { height, width } = getAssetByID(source);
|
||||
return { height, width };
|
||||
} else if (source != null && !Array.isArray(source) && typeof source === 'object') {
|
||||
} else if (
|
||||
source != null &&
|
||||
!Array.isArray(source) &&
|
||||
typeof source === 'object'
|
||||
) {
|
||||
const { height, width } = source;
|
||||
return { height, width };
|
||||
}
|
||||
@@ -107,11 +118,15 @@ function resolveAssetUri(source): ?string {
|
||||
const preferredScale = PixelRatio.get();
|
||||
// Get the scale which is closest to the preferred scale
|
||||
scale = asset.scales.reduce((prev, curr) =>
|
||||
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale) ? curr : prev
|
||||
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale)
|
||||
? curr
|
||||
: prev
|
||||
);
|
||||
}
|
||||
const scaleSuffix = scale !== 1 ? `@${scale}x` : '';
|
||||
uri = asset ? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}` : '';
|
||||
uri = asset
|
||||
? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}`
|
||||
: '';
|
||||
} else if (typeof source === 'string') {
|
||||
uri = source;
|
||||
} else if (source && typeof source.uri === 'string') {
|
||||
@@ -138,168 +153,184 @@ interface ImageStatics {
|
||||
failure: () => void
|
||||
) => void;
|
||||
prefetch: (uri: string) => Promise<void>;
|
||||
queryCache: (uris: Array<string>) => Promise<{| [uri: string]: 'disk/memory' |}>;
|
||||
queryCache: (
|
||||
uris: Array<string>
|
||||
) => Promise<{| [uri: string]: 'disk/memory' |}>;
|
||||
}
|
||||
|
||||
const Image: React.AbstractComponent<ImageProps, React.ElementRef<typeof View>> = React.forwardRef(
|
||||
(props, ref) => {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
blurRadius,
|
||||
defaultSource,
|
||||
draggable,
|
||||
onError,
|
||||
onLayout,
|
||||
onLoad,
|
||||
onLoadEnd,
|
||||
onLoadStart,
|
||||
pointerEvents,
|
||||
source,
|
||||
style,
|
||||
...rest
|
||||
} = props;
|
||||
const Image: React.AbstractComponent<
|
||||
ImageProps,
|
||||
React.ElementRef<typeof View>
|
||||
> = React.forwardRef((props, ref) => {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
blurRadius,
|
||||
defaultSource,
|
||||
draggable,
|
||||
onError,
|
||||
onLayout,
|
||||
onLoad,
|
||||
onLoadEnd,
|
||||
onLoadStart,
|
||||
pointerEvents,
|
||||
source,
|
||||
style,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (props.children) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.'
|
||||
);
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (props.children) {
|
||||
throw new Error(
|
||||
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.'
|
||||
);
|
||||
}
|
||||
|
||||
const [state, updateState] = React.useState(() => {
|
||||
const uri = resolveAssetUri(source);
|
||||
if (uri != null) {
|
||||
const isLoaded = ImageLoader.has(uri);
|
||||
if (isLoaded) {
|
||||
return LOADED;
|
||||
}
|
||||
}
|
||||
return IDLE;
|
||||
});
|
||||
|
||||
const [layout, updateLayout] = React.useState({});
|
||||
const hasTextAncestor = React.useContext(TextAncestorContext);
|
||||
const hiddenImageRef = React.useRef(null);
|
||||
const filterRef = React.useRef(_filterId++);
|
||||
const requestRef = React.useRef(null);
|
||||
const shouldDisplaySource = state === LOADED || (state === LOADING && defaultSource == null);
|
||||
const [flatStyle, _resizeMode, filter, tintColor] = getFlatStyle(
|
||||
style,
|
||||
blurRadius,
|
||||
filterRef.current
|
||||
);
|
||||
const resizeMode = props.resizeMode || _resizeMode || 'cover';
|
||||
const selectedSource = shouldDisplaySource ? source : defaultSource;
|
||||
const displayImageUri = resolveAssetUri(selectedSource);
|
||||
const imageSizeStyle = resolveAssetDimensions(selectedSource);
|
||||
const backgroundImage = displayImageUri ? `url("${displayImageUri}")` : null;
|
||||
const backgroundSize = getBackgroundSize();
|
||||
|
||||
// Accessibility image allows users to trigger the browser's image context menu
|
||||
const hiddenImage = displayImageUri
|
||||
? createElement('img', {
|
||||
alt: accessibilityLabel || '',
|
||||
style: styles.accessibilityImage$raw,
|
||||
draggable: draggable || false,
|
||||
ref: hiddenImageRef,
|
||||
src: displayImageUri
|
||||
})
|
||||
: null;
|
||||
|
||||
function getBackgroundSize(): ?string {
|
||||
if (hiddenImageRef.current != null && (resizeMode === 'center' || resizeMode === 'repeat')) {
|
||||
const { naturalHeight, naturalWidth } = hiddenImageRef.current;
|
||||
const { height, width } = layout;
|
||||
if (naturalHeight && naturalWidth && height && width) {
|
||||
const scaleFactor = Math.min(1, width / naturalWidth, height / naturalHeight);
|
||||
const x = Math.ceil(scaleFactor * naturalWidth);
|
||||
const y = Math.ceil(scaleFactor * naturalHeight);
|
||||
return `${x}px ${y}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleLayout(e) {
|
||||
if (resizeMode === 'center' || resizeMode === 'repeat' || onLayout) {
|
||||
const { layout } = e.nativeEvent;
|
||||
onLayout && onLayout(e);
|
||||
updateLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
// Image loading
|
||||
const uri = resolveAssetUri(source);
|
||||
React.useEffect(() => {
|
||||
abortPendingRequest();
|
||||
|
||||
if (uri != null) {
|
||||
updateState(LOADING);
|
||||
if (onLoadStart) {
|
||||
onLoadStart();
|
||||
}
|
||||
|
||||
requestRef.current = ImageLoader.load(
|
||||
uri,
|
||||
function load(e) {
|
||||
updateState(LOADED);
|
||||
if (onLoad) {
|
||||
onLoad(e);
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
},
|
||||
function error() {
|
||||
updateState(ERRORED);
|
||||
if (onError) {
|
||||
onError({
|
||||
nativeEvent: {
|
||||
error: `Failed to load resource ${uri} (404)`
|
||||
}
|
||||
});
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function abortPendingRequest() {
|
||||
if (requestRef.current != null) {
|
||||
ImageLoader.abort(requestRef.current);
|
||||
requestRef.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
return abortPendingRequest;
|
||||
}, [uri, requestRef, updateState, onError, onLoad, onLoadEnd, onLoadStart]);
|
||||
|
||||
return (
|
||||
<View
|
||||
{...rest}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onLayout={handleLayout}
|
||||
pointerEvents={pointerEvents}
|
||||
ref={ref}
|
||||
style={[styles.root, hasTextAncestor && styles.inline, imageSizeStyle, flatStyle]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.image,
|
||||
resizeModeStyles[resizeMode],
|
||||
{ backgroundImage, filter },
|
||||
backgroundSize != null && { backgroundSize }
|
||||
]}
|
||||
suppressHydrationWarning={true}
|
||||
/>
|
||||
{hiddenImage}
|
||||
{createTintColorSVG(tintColor, filterRef.current)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const [state, updateState] = React.useState(() => {
|
||||
const uri = resolveAssetUri(source);
|
||||
if (uri != null) {
|
||||
const isLoaded = ImageLoader.has(uri);
|
||||
if (isLoaded) {
|
||||
return LOADED;
|
||||
}
|
||||
}
|
||||
return IDLE;
|
||||
});
|
||||
|
||||
const [layout, updateLayout] = React.useState({});
|
||||
const hasTextAncestor = React.useContext(TextAncestorContext);
|
||||
const hiddenImageRef = React.useRef(null);
|
||||
const filterRef = React.useRef(_filterId++);
|
||||
const requestRef = React.useRef(null);
|
||||
const shouldDisplaySource =
|
||||
state === LOADED || (state === LOADING && defaultSource == null);
|
||||
const [flatStyle, _resizeMode, filter, tintColor] = getFlatStyle(
|
||||
style,
|
||||
blurRadius,
|
||||
filterRef.current
|
||||
);
|
||||
const resizeMode = props.resizeMode || _resizeMode || 'cover';
|
||||
const selectedSource = shouldDisplaySource ? source : defaultSource;
|
||||
const displayImageUri = resolveAssetUri(selectedSource);
|
||||
const imageSizeStyle = resolveAssetDimensions(selectedSource);
|
||||
const backgroundImage = displayImageUri ? `url("${displayImageUri}")` : null;
|
||||
const backgroundSize = getBackgroundSize();
|
||||
|
||||
// Accessibility image allows users to trigger the browser's image context menu
|
||||
const hiddenImage = displayImageUri
|
||||
? createElement('img', {
|
||||
alt: accessibilityLabel || '',
|
||||
style: styles.accessibilityImage$raw,
|
||||
draggable: draggable || false,
|
||||
ref: hiddenImageRef,
|
||||
src: displayImageUri
|
||||
})
|
||||
: null;
|
||||
|
||||
function getBackgroundSize(): ?string {
|
||||
if (
|
||||
hiddenImageRef.current != null &&
|
||||
(resizeMode === 'center' || resizeMode === 'repeat')
|
||||
) {
|
||||
const { naturalHeight, naturalWidth } = hiddenImageRef.current;
|
||||
const { height, width } = layout;
|
||||
if (naturalHeight && naturalWidth && height && width) {
|
||||
const scaleFactor = Math.min(
|
||||
1,
|
||||
width / naturalWidth,
|
||||
height / naturalHeight
|
||||
);
|
||||
const x = Math.ceil(scaleFactor * naturalWidth);
|
||||
const y = Math.ceil(scaleFactor * naturalHeight);
|
||||
return `${x}px ${y}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleLayout(e) {
|
||||
if (resizeMode === 'center' || resizeMode === 'repeat' || onLayout) {
|
||||
const { layout } = e.nativeEvent;
|
||||
onLayout && onLayout(e);
|
||||
updateLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
// Image loading
|
||||
const uri = resolveAssetUri(source);
|
||||
React.useEffect(() => {
|
||||
abortPendingRequest();
|
||||
|
||||
if (uri != null) {
|
||||
updateState(LOADING);
|
||||
if (onLoadStart) {
|
||||
onLoadStart();
|
||||
}
|
||||
|
||||
requestRef.current = ImageLoader.load(
|
||||
uri,
|
||||
function load(e) {
|
||||
updateState(LOADED);
|
||||
if (onLoad) {
|
||||
onLoad(e);
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
},
|
||||
function error() {
|
||||
updateState(ERRORED);
|
||||
if (onError) {
|
||||
onError({
|
||||
nativeEvent: {
|
||||
error: `Failed to load resource ${uri} (404)`
|
||||
}
|
||||
});
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function abortPendingRequest() {
|
||||
if (requestRef.current != null) {
|
||||
ImageLoader.abort(requestRef.current);
|
||||
requestRef.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
return abortPendingRequest;
|
||||
}, [uri, requestRef, updateState, onError, onLoad, onLoadEnd, onLoadStart]);
|
||||
|
||||
return (
|
||||
<View
|
||||
{...rest}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onLayout={handleLayout}
|
||||
pointerEvents={pointerEvents}
|
||||
ref={ref}
|
||||
style={[
|
||||
styles.root,
|
||||
hasTextAncestor && styles.inline,
|
||||
imageSizeStyle,
|
||||
flatStyle
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.image,
|
||||
resizeModeStyles[resizeMode],
|
||||
{ backgroundImage, filter },
|
||||
backgroundSize != null && { backgroundSize }
|
||||
]}
|
||||
suppressHydrationWarning={true}
|
||||
/>
|
||||
{hiddenImage}
|
||||
{createTintColorSVG(tintColor, filterRef.current)}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
Image.displayName = 'Image';
|
||||
|
||||
|
||||
@@ -77,7 +77,13 @@ type SourceObject = {
|
||||
width?: number
|
||||
};
|
||||
|
||||
export type ResizeMode = 'center' | 'contain' | 'cover' | 'none' | 'repeat' | 'stretch';
|
||||
export type ResizeMode =
|
||||
| 'center'
|
||||
| 'contain'
|
||||
| 'cover'
|
||||
| 'none'
|
||||
| 'repeat'
|
||||
| 'stretch';
|
||||
|
||||
export type Source = number | string | SourceObject | Array<SourceObject>;
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ describe('components/ImageBackground', () => {
|
||||
const imageStyle = { width: 40, height: 60 };
|
||||
const { container } = render(<ImageBackground imageStyle={imageStyle} />);
|
||||
expect(
|
||||
findImage(container).getAttribute('style').includes('width: 40px; height: 60px;')
|
||||
findImage(container)
|
||||
.getAttribute('style')
|
||||
.includes('width: 40px; height: 60px;')
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -40,7 +42,9 @@ describe('components/ImageBackground', () => {
|
||||
test('sets the style of the container View', () => {
|
||||
const style = { margin: 40 };
|
||||
const { container } = render(<ImageBackground style={style} />);
|
||||
expect(container.firstChild.getAttribute('style')).toEqual('margin: 40px 40px 40px 40px;');
|
||||
expect(container.firstChild.getAttribute('style')).toEqual(
|
||||
'margin: 40px 40px 40px 40px;'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,7 +32,13 @@ const ImageBackground: React.AbstractComponent<
|
||||
ImageBackgroundProps,
|
||||
React.ElementRef<typeof View>
|
||||
> = forwardRef((props, forwardedRef) => {
|
||||
const { children, style = emptyObject, imageStyle, imageRef, ...rest } = props;
|
||||
const {
|
||||
children,
|
||||
style = emptyObject,
|
||||
imageStyle,
|
||||
imageRef,
|
||||
...rest
|
||||
} = props;
|
||||
const { height, width } = StyleSheet.flatten(style);
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import requestIdleCallback, { cancelIdleCallback } from '../../modules/requestIdleCallback';
|
||||
import requestIdleCallback, {
|
||||
cancelIdleCallback
|
||||
} from '../../modules/requestIdleCallback';
|
||||
|
||||
const InteractionManager = {
|
||||
Events: {
|
||||
@@ -20,7 +22,11 @@ const InteractionManager = {
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed.
|
||||
*/
|
||||
runAfterInteractions(task: ?Function): { then: Function, done: Function, cancel: Function } {
|
||||
runAfterInteractions(task: ?Function): {
|
||||
then: Function,
|
||||
done: Function,
|
||||
cancel: Function
|
||||
} {
|
||||
let handle;
|
||||
|
||||
const promise = new Promise((resolve) => {
|
||||
|
||||
@@ -29,7 +29,8 @@ class KeyboardAvoidingView extends React.Component<KeyboardAvoidingViewProps> {
|
||||
if (!frame || !keyboardFrame) {
|
||||
return 0;
|
||||
}
|
||||
const keyboardY = keyboardFrame.screenY - (this.props.keyboardVerticalOffset || 0);
|
||||
const keyboardY =
|
||||
keyboardFrame.screenY - (this.props.keyboardVerticalOffset || 0);
|
||||
return Math.max(frame.y + frame.height - keyboardY, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,32 +5,38 @@ import Linking from '..';
|
||||
describe('apis/Linking', () => {
|
||||
describe('openURL', () => {
|
||||
test('calls open with a url and target', (done) => {
|
||||
jest.spyOn(window, 'open').mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe('target_name');
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
jest
|
||||
.spyOn(window, 'open')
|
||||
.mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe('target_name');
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
Linking.openURL('http://foo.com', 'target_name');
|
||||
});
|
||||
|
||||
test('defaults target to _blank if not provided', (done) => {
|
||||
jest.spyOn(window, 'open').mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe('_blank');
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
jest
|
||||
.spyOn(window, 'open')
|
||||
.mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe('_blank');
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
Linking.openURL('http://foo.com');
|
||||
});
|
||||
|
||||
test('accepts undefined as a target', (done) => {
|
||||
jest.spyOn(window, 'open').mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe(undefined);
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
jest
|
||||
.spyOn(window, 'open')
|
||||
.mockImplementationOnce((url, target, opener) => {
|
||||
expect(url).toBe('http://foo.com/');
|
||||
expect(target).toBe(undefined);
|
||||
expect(opener).toBe('noopener');
|
||||
done();
|
||||
});
|
||||
Linking.openURL('http://foo.com', undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,10 @@ const initialURL = canUseDOM ? window.location.href : '';
|
||||
|
||||
type Callback = (...args: any) => void;
|
||||
|
||||
type OnOpenCallback = (event: 'onOpen', callback: (url: string) => void) => void;
|
||||
type OnOpenCallback = (
|
||||
event: 'onOpen',
|
||||
callback: (url: string) => void
|
||||
) => void;
|
||||
type GenericCallback = (event: string, callback: Callback) => void;
|
||||
|
||||
class Linking {
|
||||
@@ -39,7 +42,10 @@ class Linking {
|
||||
* Adds a event listener for the specified event. The callback will be called when the
|
||||
* said event is dispatched.
|
||||
*/
|
||||
addEventListener: OnOpenCallback | GenericCallback = (event: string, callback: Callback) => {
|
||||
addEventListener: OnOpenCallback | GenericCallback = (
|
||||
event: string,
|
||||
callback: Callback
|
||||
) => {
|
||||
if (!this._eventCallbacks[event]) {
|
||||
this._eventCallbacks[event] = [callback];
|
||||
return;
|
||||
@@ -51,9 +57,14 @@ class Linking {
|
||||
* Removes a previously added event listener for the specified event. The callback must
|
||||
* be the same object as the one passed to `addEventListener`.
|
||||
*/
|
||||
removeEventListener: OnOpenCallback | GenericCallback = (event: string, callback: Callback) => {
|
||||
removeEventListener: OnOpenCallback | GenericCallback = (
|
||||
event: string,
|
||||
callback: Callback
|
||||
) => {
|
||||
const callbacks = this._eventCallbacks[event];
|
||||
const filteredCallbacks = callbacks.filter((c) => c.toString() !== callback.toString());
|
||||
const filteredCallbacks = callbacks.filter(
|
||||
(c) => c.toString() !== callback.toString()
|
||||
);
|
||||
this._eventCallbacks[event] = filteredCallbacks;
|
||||
};
|
||||
|
||||
@@ -85,7 +96,10 @@ class Linking {
|
||||
}
|
||||
|
||||
_validateURL(url: string) {
|
||||
invariant(typeof url === 'string', 'Invalid URL: should be a string. Was: ' + url);
|
||||
invariant(
|
||||
typeof url === 'string',
|
||||
'Invalid URL: should be a string. Was: ' + url
|
||||
);
|
||||
invariant(url, 'Invalid URL: cannot be empty');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,9 @@ function ModalAnimation(props: ModalAnimationProps): React.Node {
|
||||
|
||||
return isRendering || visible
|
||||
? createElement('div', {
|
||||
style: isRendering ? getAnimationStyle(animationType, visible) : styles.hidden,
|
||||
style: isRendering
|
||||
? getAnimationStyle(animationType, visible)
|
||||
: styles.hidden,
|
||||
onAnimationEnd: animationEndCallback,
|
||||
children
|
||||
})
|
||||
@@ -133,9 +135,25 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
const animatedSlideInStyles = [styles.container, styles.animatedIn, styles.slideIn];
|
||||
const animatedSlideOutStyles = [styles.container, styles.animatedOut, styles.slideOut];
|
||||
const animatedFadeInStyles = [styles.container, styles.animatedIn, styles.fadeIn];
|
||||
const animatedFadeOutStyles = [styles.container, styles.animatedOut, styles.fadeOut];
|
||||
const animatedSlideInStyles = [
|
||||
styles.container,
|
||||
styles.animatedIn,
|
||||
styles.slideIn
|
||||
];
|
||||
const animatedSlideOutStyles = [
|
||||
styles.container,
|
||||
styles.animatedOut,
|
||||
styles.slideOut
|
||||
];
|
||||
const animatedFadeInStyles = [
|
||||
styles.container,
|
||||
styles.animatedIn,
|
||||
styles.fadeIn
|
||||
];
|
||||
const animatedFadeOutStyles = [
|
||||
styles.container,
|
||||
styles.animatedOut,
|
||||
styles.fadeOut
|
||||
];
|
||||
|
||||
export default ModalAnimation;
|
||||
|
||||
@@ -46,7 +46,10 @@ const ModalContent: React.AbstractComponent<
|
||||
}, [active, onRequestClose]);
|
||||
|
||||
const style = React.useMemo(() => {
|
||||
return [styles.modal, transparent ? styles.modalTransparent : styles.modalOpaque];
|
||||
return [
|
||||
styles.modal,
|
||||
transparent ? styles.modalTransparent : styles.modalOpaque
|
||||
];
|
||||
}, [transparent]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -71,14 +71,18 @@ export type ModalFocusTrapProps = {|
|
||||
children?: any
|
||||
|};
|
||||
|
||||
const ModalFocusTrap = ({ active, children }: ModalFocusTrapProps): React.Node => {
|
||||
const ModalFocusTrap = ({
|
||||
active,
|
||||
children
|
||||
}: ModalFocusTrapProps): React.Node => {
|
||||
const trapElementRef = React.useRef<?HTMLElement>();
|
||||
const focusRef = React.useRef<{ trapFocusInProgress: boolean, lastFocusedElement: ?HTMLElement }>(
|
||||
{
|
||||
trapFocusInProgress: false,
|
||||
lastFocusedElement: null
|
||||
}
|
||||
);
|
||||
const focusRef = React.useRef<{
|
||||
trapFocusInProgress: boolean,
|
||||
lastFocusedElement: ?HTMLElement
|
||||
}>({
|
||||
trapFocusInProgress: false,
|
||||
lastFocusedElement: null
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (canUseDOM) {
|
||||
@@ -87,7 +91,11 @@ const ModalFocusTrap = ({ active, children }: ModalFocusTrapProps): React.Node =
|
||||
// - The modal hasn't fully initialized with an HTMLElement ref
|
||||
// - Focus is already in the process of being trapped (e.g., we're refocusing)
|
||||
// - isTrapActive prop being falsey tells us to do nothing
|
||||
if (trapElementRef.current == null || focusRef.current.trapFocusInProgress || !active) {
|
||||
if (
|
||||
trapElementRef.current == null ||
|
||||
focusRef.current.trapFocusInProgress ||
|
||||
!active
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,11 +112,17 @@ const ModalFocusTrap = ({ active, children }: ModalFocusTrapProps): React.Node =
|
||||
// and we're leaving it - this means that we should be looping
|
||||
// around to the other side of the modal.
|
||||
let hasFocused = focusFirstDescendant(trapElementRef.current);
|
||||
if (focusRef.current.lastFocusedElement === document.activeElement) {
|
||||
if (
|
||||
focusRef.current.lastFocusedElement === document.activeElement
|
||||
) {
|
||||
hasFocused = focusLastDescendant(trapElementRef.current);
|
||||
}
|
||||
// If we couldn't focus a new element then we need to focus onto the trap target
|
||||
if (!hasFocused && trapElementRef.current != null && document.activeElement) {
|
||||
if (
|
||||
!hasFocused &&
|
||||
trapElementRef.current != null &&
|
||||
document.activeElement
|
||||
) {
|
||||
UIManager.focus(trapElementRef.current);
|
||||
}
|
||||
}
|
||||
@@ -132,7 +146,10 @@ const ModalFocusTrap = ({ active, children }: ModalFocusTrapProps): React.Node =
|
||||
if (canUseDOM) {
|
||||
const lastFocusedElementOutsideTrap = document.activeElement;
|
||||
return function () {
|
||||
if (lastFocusedElementOutsideTrap && document.contains(lastFocusedElementOutsideTrap)) {
|
||||
if (
|
||||
lastFocusedElementOutsideTrap &&
|
||||
document.contains(lastFocusedElementOutsideTrap)
|
||||
) {
|
||||
UIManager.focus(lastFocusedElementOutsideTrap);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,7 +25,11 @@ describe('components/Modal', () => {
|
||||
|
||||
test('forwards props', () => {
|
||||
const { getByTestId } = render(
|
||||
<Modal accessibilityLabel="label" accessibilityLabelledBy="labelledby" testID="root" />
|
||||
<Modal
|
||||
accessibilityLabel="label"
|
||||
accessibilityLabelledBy="labelledby"
|
||||
testID="root"
|
||||
/>
|
||||
);
|
||||
expect(getByTestId('root')).toMatchSnapshot();
|
||||
});
|
||||
@@ -189,7 +193,9 @@ describe('components/Modal', () => {
|
||||
|
||||
test('executes onShow callback when visibility changes', () => {
|
||||
const onShowCallback = jest.fn();
|
||||
const { rerender } = render(<Modal onShow={onShowCallback} visible={false} />);
|
||||
const { rerender } = render(
|
||||
<Modal onShow={onShowCallback} visible={false} />
|
||||
);
|
||||
expect(onShowCallback).toBeCalledTimes(0);
|
||||
rerender(<Modal onShow={onShowCallback} visible={true} />);
|
||||
expect(onShowCallback).toBeCalledTimes(1);
|
||||
@@ -197,19 +203,29 @@ describe('components/Modal', () => {
|
||||
|
||||
test('executes onDismiss callback when visibility changes', () => {
|
||||
const onDismissCallback = jest.fn();
|
||||
const { rerender } = render(<Modal onDismiss={onDismissCallback} visible={true} />);
|
||||
const { rerender } = render(
|
||||
<Modal onDismiss={onDismissCallback} visible={true} />
|
||||
);
|
||||
expect(onDismissCallback).toBeCalledTimes(0);
|
||||
rerender(<Modal onDismiss={onDismissCallback} visible={false} />);
|
||||
expect(onDismissCallback).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('animationTypes none is the same as omitting', () => {
|
||||
const { rerender, baseElement } = render(<Modal animationType={'none'} visible={true} />);
|
||||
const { rerender, baseElement } = render(
|
||||
<Modal animationType={'none'} visible={true} />
|
||||
);
|
||||
const animationNoneElement = baseElement.lastChild.lastChild;
|
||||
const animationNoneStyle = window.getComputedStyle(animationNoneElement, null);
|
||||
const animationNoneStyle = window.getComputedStyle(
|
||||
animationNoneElement,
|
||||
null
|
||||
);
|
||||
rerender(<Modal visible={true} />);
|
||||
const animationMissingElement = baseElement.lastChild.lastChild;
|
||||
const animationMissingStyle = window.getComputedStyle(animationMissingElement, null);
|
||||
const animationMissingStyle = window.getComputedStyle(
|
||||
animationMissingElement,
|
||||
null
|
||||
);
|
||||
const styleProps = new Set();
|
||||
|
||||
for (let i = 0; i < animationNoneStyle.length; i++) {
|
||||
@@ -231,7 +247,8 @@ describe('components/Modal', () => {
|
||||
<a href={'#hello'}>Hello</a>
|
||||
</Modal>
|
||||
);
|
||||
const dialogElement = baseElement.lastChild.querySelector('[role="dialog"]');
|
||||
const dialogElement =
|
||||
baseElement.lastChild.querySelector('[role="dialog"]');
|
||||
expect(dialogElement).not.toBeNull();
|
||||
expect(dialogElement.getAttribute('role')).toBe('dialog');
|
||||
expect(dialogElement.getAttribute('aria-modal')).toBe('true');
|
||||
@@ -309,7 +326,9 @@ describe('components/Modal', () => {
|
||||
</>
|
||||
);
|
||||
|
||||
const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
|
||||
const modalTrigger = document.querySelector(
|
||||
'[data-testid="modal-trigger"]'
|
||||
);
|
||||
modalTrigger.focus();
|
||||
expect(document.activeElement).toBe(modalTrigger);
|
||||
|
||||
@@ -368,7 +387,9 @@ describe('components/Modal', () => {
|
||||
</>
|
||||
);
|
||||
|
||||
const modalTrigger = document.querySelector('[data-testid="modal-trigger"]');
|
||||
const modalTrigger = document.querySelector(
|
||||
'[data-testid="modal-trigger"]'
|
||||
);
|
||||
modalTrigger.focus();
|
||||
expect(document.activeElement).toBe(modalTrigger);
|
||||
|
||||
@@ -444,10 +465,13 @@ describe('components/Modal', () => {
|
||||
</>
|
||||
);
|
||||
|
||||
const insideStartElement = document.querySelector('[data-testid="inside-a"]');
|
||||
const insideStartElement = document.querySelector(
|
||||
'[data-testid="inside-a"]'
|
||||
);
|
||||
const insideEndElement = document.querySelector('[data-testid="inside-c"]');
|
||||
// This is ugly - perhaps there's a better way?
|
||||
const focusBracket = insideEndElement.parentNode.parentNode.parentNode.nextSibling;
|
||||
const focusBracket =
|
||||
insideEndElement.parentNode.parentNode.parentNode.nextSibling;
|
||||
insideEndElement.focus();
|
||||
focusBracket.focus();
|
||||
expect(document.activeElement).toBe(insideStartElement);
|
||||
@@ -470,10 +494,13 @@ describe('components/Modal', () => {
|
||||
</>
|
||||
);
|
||||
|
||||
const insideStartElement = document.querySelector('[data-testid="inside-a"]');
|
||||
const insideStartElement = document.querySelector(
|
||||
'[data-testid="inside-a"]'
|
||||
);
|
||||
const insideEndElement = document.querySelector('[data-testid="inside-c"]');
|
||||
// This is ugly - perhaps there's a better way?
|
||||
const focusBracket = insideEndElement.parentNode.parentNode.parentNode.previousSibling;
|
||||
const focusBracket =
|
||||
insideEndElement.parentNode.parentNode.parentNode.previousSibling;
|
||||
insideStartElement.focus();
|
||||
focusBracket.focus();
|
||||
expect(document.activeElement).toBe(insideEndElement);
|
||||
@@ -614,10 +641,10 @@ describe('components/Modal', () => {
|
||||
);
|
||||
|
||||
// This is kind of ugly but I can't find a better way to target just the animation div
|
||||
const animationAElement = getByTestId('a').parentElement.parentElement.parentElement
|
||||
.parentElement;
|
||||
const animationBElement = getByTestId('b').parentElement.parentElement.parentElement
|
||||
.parentElement;
|
||||
const animationAElement =
|
||||
getByTestId('a').parentElement.parentElement.parentElement.parentElement;
|
||||
const animationBElement =
|
||||
getByTestId('b').parentElement.parentElement.parentElement.parentElement;
|
||||
|
||||
fireEvent.animationEnd(animationAElement);
|
||||
fireEvent.animationEnd(animationBElement);
|
||||
|
||||
@@ -22,13 +22,24 @@ export type ModalProps = {
|
||||
children: any,
|
||||
hardwareAccelerated?: ?boolean,
|
||||
onDismiss?: ?() => mixed,
|
||||
onOrientationChange?: ?(e: {| orientation: 'portrait' | 'landscape' |}) => void,
|
||||
onOrientationChange?: ?(e: {|
|
||||
orientation: 'portrait' | 'landscape'
|
||||
|}) => void,
|
||||
onRequestClose?: ?() => void,
|
||||
onShow?: ?() => void,
|
||||
presentationStyle?: ?('fullScreen' | 'pageSheet' | 'formSheet' | 'overFullScreen'),
|
||||
presentationStyle?: ?(
|
||||
| 'fullScreen'
|
||||
| 'pageSheet'
|
||||
| 'formSheet'
|
||||
| 'overFullScreen'
|
||||
),
|
||||
statusBarTranslucent?: ?boolean,
|
||||
supportedOrientations?: ?Array<
|
||||
'portrait' | 'portrait-upside-down' | 'landscape' | 'landscape-left' | 'landscape-right'
|
||||
| 'portrait'
|
||||
| 'portrait-upside-down'
|
||||
| 'landscape'
|
||||
| 'landscape-left'
|
||||
| 'landscape-right'
|
||||
>,
|
||||
transparent?: ?boolean,
|
||||
visible?: ?boolean
|
||||
|
||||
@@ -80,7 +80,10 @@ export type GestureState = {|
|
||||
_accountsForMovesUpTo: number
|
||||
|};
|
||||
|
||||
type ActiveCallback = (event: PressEvent, gestureState: GestureState) => boolean;
|
||||
type ActiveCallback = (
|
||||
event: PressEvent,
|
||||
gestureState: GestureState
|
||||
) => boolean;
|
||||
type PassiveCallback = (event: PressEvent, gestureState: GestureState) => void;
|
||||
|
||||
type PanResponderConfig = $ReadOnly<{|
|
||||
@@ -171,8 +174,14 @@ const PanResponder = {
|
||||
touchHistory: $PropertyType<PressEvent, 'touchHistory'>
|
||||
) {
|
||||
const movedAfter = gestureState._accountsForMovesUpTo;
|
||||
const prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const prevX = previousCentroidXOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
movedAfter
|
||||
);
|
||||
const prevY = previousCentroidYOfTouchesChangedAfter(
|
||||
touchHistory,
|
||||
movedAfter
|
||||
);
|
||||
const prevDeltaX = gestureState.deltaX;
|
||||
const prevDeltaY = gestureState.deltaY;
|
||||
|
||||
@@ -181,7 +190,8 @@ const PanResponder = {
|
||||
const deltaX = prevDeltaX + (x - prevX);
|
||||
const deltaY = prevDeltaY + (y - prevY);
|
||||
// TODO: This must be filtered intelligently.
|
||||
const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
const dt =
|
||||
touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
|
||||
gestureState.deltaX = deltaX;
|
||||
gestureState.deltaY = deltaY;
|
||||
@@ -201,9 +211,7 @@ const PanResponder = {
|
||||
* gestureState once in the capture phase and can use it in the bubble phase
|
||||
* as well.
|
||||
*/
|
||||
create(
|
||||
config: PanResponderConfig
|
||||
): {|
|
||||
create(config: PanResponderConfig): {|
|
||||
getInteractionHandle: () => ?number,
|
||||
panHandlers: {|
|
||||
onMoveShouldSetResponder: (event: PressEvent) => boolean,
|
||||
@@ -270,7 +278,8 @@ const PanResponder = {
|
||||
if (event.nativeEvent.touches.length === 1) {
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
}
|
||||
gestureState.numberActiveTouches = event.touchHistory.numberActiveTouches;
|
||||
gestureState.numberActiveTouches =
|
||||
event.touchHistory.numberActiveTouches;
|
||||
return onStartShouldSetResponderCapture != null
|
||||
? onStartShouldSetResponderCapture(event, gestureState)
|
||||
: false;
|
||||
@@ -293,7 +302,8 @@ const PanResponder = {
|
||||
|
||||
onResponderGrant(event: PressEvent): void {
|
||||
if (!interactionState.handle) {
|
||||
interactionState.handle = InteractionManager.createInteractionHandle();
|
||||
interactionState.handle =
|
||||
InteractionManager.createInteractionHandle();
|
||||
}
|
||||
gestureState.initialX = currentCentroidX(event.touchHistory);
|
||||
gestureState.initialY = currentCentroidY(event.touchHistory);
|
||||
@@ -305,7 +315,12 @@ const PanResponder = {
|
||||
},
|
||||
|
||||
onResponderReject(event: PressEvent): void {
|
||||
clearInteractionHandle(interactionState, onPanReject, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
onPanReject,
|
||||
event,
|
||||
gestureState
|
||||
);
|
||||
},
|
||||
|
||||
onResponderStart(event: PressEvent): void {
|
||||
@@ -320,7 +335,10 @@ const PanResponder = {
|
||||
const touchHistory = event.touchHistory;
|
||||
// Guard against the dispatch of two touch moves when there are two
|
||||
// simultaneously changed touches.
|
||||
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
|
||||
if (
|
||||
gestureState._accountsForMovesUpTo ===
|
||||
touchHistory.mostRecentTimeStamp
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
@@ -338,12 +356,22 @@ const PanResponder = {
|
||||
},
|
||||
|
||||
onResponderRelease(event: PressEvent): void {
|
||||
clearInteractionHandle(interactionState, onPanRelease, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
onPanRelease,
|
||||
event,
|
||||
gestureState
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
onResponderTerminate(event: PressEvent): void {
|
||||
clearInteractionHandle(interactionState, onPanTerminate, event, gestureState);
|
||||
clearInteractionHandle(
|
||||
interactionState,
|
||||
onPanTerminate,
|
||||
event,
|
||||
gestureState
|
||||
);
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
},
|
||||
|
||||
|
||||
@@ -15,7 +15,12 @@ describe('apis/Platform', () => {
|
||||
|
||||
test('chooses "web"', () => {
|
||||
expect(
|
||||
Platform.select({ android: 'android', ios: 'ios', web: 'web', default: 'default' })
|
||||
Platform.select({
|
||||
android: 'android',
|
||||
ios: 'ios',
|
||||
web: 'web',
|
||||
default: 'default'
|
||||
})
|
||||
).toEqual('web');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,9 @@ describe('components/Pressable', () => {
|
||||
|
||||
describe('prop "accessibilityLiveRegion"', () => {
|
||||
test('value is set', () => {
|
||||
const { container } = render(<Pressable accessibilityLiveRegion="polite" />);
|
||||
const { container } = render(
|
||||
<Pressable accessibilityLiveRegion="polite" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -73,7 +75,9 @@ describe('components/Pressable', () => {
|
||||
act(() => {
|
||||
({ container } = render(
|
||||
<Pressable
|
||||
children={({ focused }) => (focused ? <div data-testid="focus-content" /> : null)}
|
||||
children={({ focused }) =>
|
||||
focused ? <div data-testid="focus-content" /> : null
|
||||
}
|
||||
onBlur={onBlur}
|
||||
onFocus={onFocus}
|
||||
ref={ref}
|
||||
@@ -101,7 +105,14 @@ describe('components/Pressable', () => {
|
||||
const onFocus = jest.fn();
|
||||
const ref = React.createRef();
|
||||
act(() => {
|
||||
render(<Pressable disabled={true} onBlur={onBlur} onFocus={onFocus} ref={ref} />);
|
||||
render(
|
||||
<Pressable
|
||||
disabled={true}
|
||||
onBlur={onBlur}
|
||||
onFocus={onFocus}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const target = createEventTarget(ref.current);
|
||||
const body = createEventTarget(document.body);
|
||||
@@ -123,7 +134,9 @@ describe('components/Pressable', () => {
|
||||
act(() => {
|
||||
({ container } = render(
|
||||
<Pressable
|
||||
children={({ hovered }) => (hovered ? <div data-testid="hover-content" /> : null)}
|
||||
children={({ hovered }) =>
|
||||
hovered ? <div data-testid="hover-content" /> : null
|
||||
}
|
||||
onHoverIn={onHoverIn}
|
||||
onHoverOut={onHoverOut}
|
||||
ref={ref}
|
||||
@@ -155,7 +168,9 @@ describe('components/Pressable', () => {
|
||||
act(() => {
|
||||
({ container } = render(
|
||||
<Pressable
|
||||
children={({ pressed }) => (pressed ? <div data-testid="press-content" /> : null)}
|
||||
children={({ pressed }) =>
|
||||
pressed ? <div data-testid="press-content" /> : null
|
||||
}
|
||||
onContextMenu={onContextMenu}
|
||||
onPress={onPress}
|
||||
onPressIn={onPressIn}
|
||||
@@ -197,7 +212,9 @@ describe('components/Pressable', () => {
|
||||
const [shown, setShown] = React.useState(true);
|
||||
return shown ? (
|
||||
<Pressable
|
||||
children={({ pressed }) => (pressed ? <div data-testid="press-content" /> : null)}
|
||||
children={({ pressed }) =>
|
||||
pressed ? <div data-testid="press-content" /> : null
|
||||
}
|
||||
onPress={(e) => {
|
||||
onPress(e);
|
||||
setShown(false);
|
||||
|
||||
@@ -129,7 +129,8 @@ function Pressable(props: Props, forwardedRef): React.Node {
|
||||
|
||||
const pressEventHandlers = usePressEvents(hostRef, pressConfig);
|
||||
|
||||
const { onContextMenu: onContextMenuPress, onKeyDown: onKeyDownPress } = pressEventHandlers;
|
||||
const { onContextMenu: onContextMenuPress, onKeyDown: onKeyDownPress } =
|
||||
pressEventHandlers;
|
||||
|
||||
useHover(hostRef, {
|
||||
contain: true,
|
||||
@@ -232,4 +233,7 @@ const styles = StyleSheet.create({
|
||||
const MemoedPressable = memo(forwardRef(Pressable));
|
||||
MemoedPressable.displayName = 'Pressable';
|
||||
|
||||
export default (MemoedPressable: React.AbstractComponent<Props, React.ElementRef<typeof View>>);
|
||||
export default (MemoedPressable: React.AbstractComponent<
|
||||
Props,
|
||||
React.ElementRef<typeof View>
|
||||
>);
|
||||
|
||||
@@ -17,7 +17,9 @@ describe('components/ProgressBar', () => {
|
||||
});
|
||||
|
||||
test('is ignored when "indeterminate" is "true"', () => {
|
||||
const { container } = render(<ProgressBar indeterminate progress={0.5} />);
|
||||
const { container } = render(
|
||||
<ProgressBar indeterminate progress={0.5} />
|
||||
);
|
||||
expect(container.firstChild.getAttribute('aria-valuenow')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,7 +33,9 @@ const SafeAreaView: React.AbstractComponent<
|
||||
React.ElementRef<typeof View>
|
||||
> = React.forwardRef((props, ref) => {
|
||||
const { style, ...rest } = props;
|
||||
return <View {...rest} ref={ref} style={StyleSheet.compose(styles.root, style)} />;
|
||||
return (
|
||||
<View {...rest} ref={ref} style={StyleSheet.compose(styles.root, style)} />
|
||||
);
|
||||
});
|
||||
|
||||
SafeAreaView.displayName = 'SafeAreaView';
|
||||
|
||||
@@ -112,7 +112,12 @@ const ScrollViewBase: React.AbstractComponent<
|
||||
}, 100);
|
||||
if (scrollState.current.isScrolling) {
|
||||
// Scroll last tick may have changed, check if we need to notify
|
||||
if (shouldEmitScrollEvent(scrollState.current.scrollLastTick, scrollEventThrottle)) {
|
||||
if (
|
||||
shouldEmitScrollEvent(
|
||||
scrollState.current.scrollLastTick,
|
||||
scrollEventThrottle
|
||||
)
|
||||
) {
|
||||
handleScrollTick(e);
|
||||
}
|
||||
} else {
|
||||
@@ -142,7 +147,8 @@ const ScrollViewBase: React.AbstractComponent<
|
||||
}
|
||||
|
||||
const hideScrollbar =
|
||||
showsHorizontalScrollIndicator === false || showsVerticalScrollIndicator === false;
|
||||
showsHorizontalScrollIndicator === false ||
|
||||
showsVerticalScrollIndicator === false;
|
||||
|
||||
return (
|
||||
<View
|
||||
|
||||
@@ -11,7 +11,9 @@ describe('components/ScrollView', () => {
|
||||
const onScroll = jest.fn();
|
||||
const ref = React.createRef();
|
||||
act(() => {
|
||||
render(<ScrollView onScroll={onScroll} ref={ref} scrollEventThrottle={16} />);
|
||||
render(
|
||||
<ScrollView onScroll={onScroll} ref={ref} scrollEventThrottle={16} />
|
||||
);
|
||||
});
|
||||
const target = createEventTarget(findDOMNode(ref.current));
|
||||
act(() => {
|
||||
@@ -50,11 +52,15 @@ describe('components/ScrollView', () => {
|
||||
const ref = jest.fn();
|
||||
let rerender;
|
||||
act(() => {
|
||||
({ rerender } = render(<ScrollView nativeID="123" ref={ref} style={{ borderWidth: 5 }} />));
|
||||
({ rerender } = render(
|
||||
<ScrollView nativeID="123" ref={ref} style={{ borderWidth: 5 }} />
|
||||
));
|
||||
});
|
||||
expect(ref).toHaveBeenCalledTimes(1);
|
||||
act(() => {
|
||||
rerender(<ScrollView nativeID="1234" ref={ref} style={{ borderWidth: 6 }} />);
|
||||
rerender(
|
||||
<ScrollView nativeID="1234" ref={ref} style={{ borderWidth: 6 }} />
|
||||
);
|
||||
});
|
||||
expect(ref).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
@@ -83,13 +89,17 @@ describe('components/ScrollView', () => {
|
||||
expect(typeof node.scrollToEnd === 'function').toBe(true);
|
||||
expect(typeof node.flashScrollIndicators === 'function').toBe(true);
|
||||
expect(typeof node.scrollResponderZoomTo === 'function').toBe(true);
|
||||
expect(typeof node.scrollResponderScrollNativeHandleToKeyboard === 'function').toBe(true);
|
||||
expect(
|
||||
typeof node.scrollResponderScrollNativeHandleToKeyboard === 'function'
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "refreshControl"', () => {
|
||||
test('without', () => {
|
||||
const { container } = render(<ScrollView style={{ backgroundColor: 'red' }} />);
|
||||
const { container } = render(
|
||||
<ScrollView style={{ backgroundColor: 'red' }} />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
@@ -117,7 +117,8 @@ const ScrollView = ((createReactClass({
|
||||
const animated = (options && options.animated) !== false;
|
||||
const { horizontal } = this.props;
|
||||
const scrollResponder = this.getScrollResponder();
|
||||
const scrollResponderNode = scrollResponder.scrollResponderGetScrollableNode();
|
||||
const scrollResponderNode =
|
||||
scrollResponder.scrollResponderGetScrollableNode();
|
||||
const x = horizontal ? scrollResponderNode.scrollWidth : 0;
|
||||
const y = horizontal ? 0 : scrollResponderNode.scrollHeight;
|
||||
scrollResponder.scrollResponderScrollTo({ x, y, animated });
|
||||
@@ -158,11 +159,13 @@ const ScrollView = ((createReactClass({
|
||||
};
|
||||
}
|
||||
|
||||
const hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices);
|
||||
const hasStickyHeaderIndices =
|
||||
!horizontal && Array.isArray(stickyHeaderIndices);
|
||||
const children =
|
||||
hasStickyHeaderIndices || pagingEnabled
|
||||
? React.Children.map(this.props.children, (child, i) => {
|
||||
const isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1;
|
||||
const isSticky =
|
||||
hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1;
|
||||
if (child != null && (isSticky || pagingEnabled)) {
|
||||
return (
|
||||
<View
|
||||
@@ -208,12 +211,16 @@ const ScrollView = ((createReactClass({
|
||||
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
|
||||
onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
|
||||
onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
|
||||
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
|
||||
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
|
||||
onStartShouldSetResponder:
|
||||
this.scrollResponderHandleStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture:
|
||||
this.scrollResponderHandleStartShouldSetResponderCapture,
|
||||
onScrollShouldSetResponder:
|
||||
this.scrollResponderHandleScrollShouldSetResponder,
|
||||
onScroll: this._handleScroll,
|
||||
onResponderGrant: this.scrollResponderHandleResponderGrant,
|
||||
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
|
||||
onResponderTerminationRequest:
|
||||
this.scrollResponderHandleTerminationRequest,
|
||||
onResponderTerminate: this.scrollResponderHandleTerminate,
|
||||
onResponderRelease: this.scrollResponderHandleResponderRelease,
|
||||
onResponderReject: this.scrollResponderHandleResponderReject
|
||||
@@ -221,7 +228,10 @@ const ScrollView = ((createReactClass({
|
||||
|
||||
const ScrollViewClass = ScrollViewBase;
|
||||
|
||||
invariant(ScrollViewClass !== undefined, 'ScrollViewClass must not be undefined');
|
||||
invariant(
|
||||
ScrollViewClass !== undefined,
|
||||
'ScrollViewClass must not be undefined'
|
||||
);
|
||||
|
||||
const scrollView = (
|
||||
<ScrollViewClass {...props} ref={this._setScrollNodeRef}>
|
||||
@@ -230,7 +240,11 @@ const ScrollView = ((createReactClass({
|
||||
);
|
||||
|
||||
if (refreshControl) {
|
||||
return React.cloneElement(refreshControl, { style: props.style }, scrollView);
|
||||
return React.cloneElement(
|
||||
refreshControl,
|
||||
{ style: props.style },
|
||||
scrollView
|
||||
);
|
||||
}
|
||||
|
||||
return scrollView;
|
||||
@@ -280,7 +294,8 @@ const ScrollView = ((createReactClass({
|
||||
node.scrollToEnd = this.scrollToEnd;
|
||||
node.flashScrollIndicators = this.flashScrollIndicators;
|
||||
node.scrollResponderZoomTo = this.scrollResponderZoomTo;
|
||||
node.scrollResponderScrollNativeHandleToKeyboard = this.scrollResponderScrollNativeHandleToKeyboard;
|
||||
node.scrollResponderScrollNativeHandleToKeyboard =
|
||||
this.scrollResponderScrollNativeHandleToKeyboard;
|
||||
}
|
||||
const ref = mergeRefs(this.props.forwardedRef);
|
||||
ref(node);
|
||||
|
||||
@@ -24,7 +24,10 @@ class Share {
|
||||
typeof content.url === 'string' || typeof content.message === 'string',
|
||||
'At least one of URL and message is required'
|
||||
);
|
||||
invariant(typeof options === 'object' && options !== null, 'Options must be a valid object');
|
||||
invariant(
|
||||
typeof options === 'object' && options !== null,
|
||||
'Options must be a valid object'
|
||||
);
|
||||
invariant(
|
||||
!content.title || typeof content.title === 'string',
|
||||
'Invalid title: title should be a string.'
|
||||
@@ -37,7 +40,9 @@ class Share {
|
||||
url: content.url
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(new Error('Share is not supported in this browser'));
|
||||
return Promise.reject(
|
||||
new Error('Share is not supported in this browser')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
|
||||
describe('fontFamily', () => {
|
||||
test('general case', () => {
|
||||
expect(createReactDOMStyle({ fontFamily: 'Georgia, Times, serif' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ fontFamily: 'Georgia, Times, serif' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"fontFamily": "Georgia, Times, serif",
|
||||
}
|
||||
@@ -142,7 +143,8 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
});
|
||||
|
||||
test('"monospace"', () => {
|
||||
expect(createReactDOMStyle({ fontFamily: 'monospace' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ fontFamily: 'monospace' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"fontFamily": "monospace,monospace",
|
||||
}
|
||||
@@ -150,12 +152,14 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
});
|
||||
|
||||
test('"System"', () => {
|
||||
expect(createReactDOMStyle({ fontFamily: 'System' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ fontFamily: 'System' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"fontFamily": "-apple-system,BlinkMacSystemFont,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif",
|
||||
}
|
||||
`);
|
||||
expect(createReactDOMStyle({ font: '14px System' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ font: '14px System' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"font": "14px -apple-system,BlinkMacSystemFont,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif",
|
||||
}
|
||||
@@ -163,12 +167,14 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
});
|
||||
|
||||
test('"Noto, System"', () => {
|
||||
expect(createReactDOMStyle({ fontFamily: 'Noto, System' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ fontFamily: 'Noto, System' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"fontFamily": "Noto,-apple-system,BlinkMacSystemFont,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif",
|
||||
}
|
||||
`);
|
||||
expect(createReactDOMStyle({ font: '14px Noto, System' })).toMatchInlineSnapshot(`
|
||||
expect(createReactDOMStyle({ font: '14px Noto, System' }))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"font": "14px Noto, -apple-system,BlinkMacSystemFont,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif",
|
||||
}
|
||||
@@ -186,7 +192,9 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
});
|
||||
|
||||
test('fontVariant', () => {
|
||||
expect(createReactDOMStyle({ fontVariant: ['common-ligatures', 'small-caps'] })).toEqual({
|
||||
expect(
|
||||
createReactDOMStyle({ fontVariant: ['common-ligatures', 'small-caps'] })
|
||||
).toEqual({
|
||||
fontVariant: 'common-ligatures small-caps'
|
||||
});
|
||||
});
|
||||
@@ -204,7 +212,8 @@ describe('compiler/createReactDOMStyle', () => {
|
||||
describe('transform', () => {
|
||||
// passthrough if transform value is ever a string
|
||||
test('string', () => {
|
||||
const transform = 'perspective(50px) scaleX(20) translateX(20px) rotate(20deg)';
|
||||
const transform =
|
||||
'perspective(50px) scaleX(20) translateX(20px) rotate(20deg)';
|
||||
const style = { transform };
|
||||
const resolved = createReactDOMStyle(style);
|
||||
|
||||
|
||||
@@ -310,7 +310,9 @@ describe('StyleSheet/compile', () => {
|
||||
marginRight: '5px',
|
||||
paddingRight: '10px'
|
||||
};
|
||||
expect(inline(initial, isRTL)).toEqual(isRTL ? expectedRTL : expectedLTR);
|
||||
expect(inline(initial, isRTL)).toEqual(
|
||||
isRTL ? expectedRTL : expectedLTR
|
||||
);
|
||||
});
|
||||
|
||||
test(`converts "end" properties for ${dir}`, () => {
|
||||
@@ -339,7 +341,9 @@ describe('StyleSheet/compile', () => {
|
||||
marginLeft: '5px',
|
||||
paddingLeft: '10px'
|
||||
};
|
||||
expect(inline(initial, isRTL)).toEqual(isRTL ? expectedRTL : expectedLTR);
|
||||
expect(inline(initial, isRTL)).toEqual(
|
||||
isRTL ? expectedRTL : expectedLTR
|
||||
);
|
||||
});
|
||||
|
||||
test(`converts "start" values for ${dir}`, () => {
|
||||
@@ -362,7 +366,9 @@ describe('StyleSheet/compile', () => {
|
||||
textAlign: 'right',
|
||||
transitionProperty: 'right'
|
||||
};
|
||||
expect(inline(initial, isRTL)).toEqual(isRTL ? expectedRTL : expectedLTR);
|
||||
expect(inline(initial, isRTL)).toEqual(
|
||||
isRTL ? expectedRTL : expectedLTR
|
||||
);
|
||||
});
|
||||
|
||||
test(`converts "end" values for ${dir}`, () => {
|
||||
@@ -385,7 +391,9 @@ describe('StyleSheet/compile', () => {
|
||||
textAlign: 'left',
|
||||
transitionProperty: 'left'
|
||||
};
|
||||
expect(inline(initial, isRTL)).toEqual(isRTL ? expectedRTL : expectedLTR);
|
||||
expect(inline(initial, isRTL)).toEqual(
|
||||
isRTL ? expectedRTL : expectedLTR
|
||||
);
|
||||
});
|
||||
|
||||
test('end/start properties take precedence over left/right', () => {
|
||||
|
||||
@@ -140,7 +140,12 @@ describe('StyleSheet', () => {
|
||||
});
|
||||
|
||||
test('should recursively flatten arrays', () => {
|
||||
const style = StyleSheet.flatten([null, [], [{ order: 2 }, { opacity: 1 }], { order: 3 }]);
|
||||
const style = StyleSheet.flatten([
|
||||
null,
|
||||
[],
|
||||
[{ order: 2 }, { opacity: 1 }],
|
||||
{ order: 3 }
|
||||
]);
|
||||
expect(style).toMatchInlineSnapshot(`
|
||||
{
|
||||
"opacity": 1,
|
||||
@@ -240,17 +245,29 @@ describe('StyleSheet', () => {
|
||||
color: null
|
||||
};
|
||||
|
||||
const [className1, inlineStyle1] = StyleSheet([styleACompiled, styleBCompiled, styleBInline]);
|
||||
const [className1, inlineStyle1] = StyleSheet([
|
||||
styleACompiled,
|
||||
styleBCompiled,
|
||||
styleBInline
|
||||
]);
|
||||
expect(className1).toBe('display-block');
|
||||
expect(inlineStyle1).toEqual({ backgroundColor: 'rgba(0,0,255,1.00)' });
|
||||
|
||||
const [className2, inlineStyle2] = StyleSheet([styleACompiled, styleBInline, styleBCompiled]);
|
||||
expect(className2).toBe('display-block backgroundColor-green color-green');
|
||||
const [className2, inlineStyle2] = StyleSheet([
|
||||
styleACompiled,
|
||||
styleBInline,
|
||||
styleBCompiled
|
||||
]);
|
||||
expect(className2).toBe(
|
||||
'display-block backgroundColor-green color-green'
|
||||
);
|
||||
expect(inlineStyle2).toEqual(null);
|
||||
});
|
||||
|
||||
test('long form inline style properties take precedence over static shorthand properties', () => {
|
||||
const styles1 = StyleSheet.create({ test: { paddingHorizontal: '40px' } });
|
||||
const styles1 = StyleSheet.create({
|
||||
test: { paddingHorizontal: '40px' }
|
||||
});
|
||||
const inlineStyle1 = { padding: '8px', paddingHorizontal: '40px' };
|
||||
expect(StyleSheet([styles1.test, inlineStyle1])).toMatchInlineSnapshot(`
|
||||
[
|
||||
@@ -301,7 +318,8 @@ describe('StyleSheet', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(StyleSheet(inlineStyle, { writingDirection })).toMatchInlineSnapshot(`
|
||||
expect(StyleSheet(inlineStyle, { writingDirection }))
|
||||
.toMatchInlineSnapshot(`
|
||||
[
|
||||
"",
|
||||
{
|
||||
@@ -313,7 +331,10 @@ describe('StyleSheet', () => {
|
||||
`);
|
||||
expect(
|
||||
StyleSheet(
|
||||
[inlineStyle, { marginLeft: 1, marginEnd: 0, marginStart: 0, marginRight: 11 }],
|
||||
[
|
||||
inlineStyle,
|
||||
{ marginLeft: 1, marginEnd: 0, marginStart: 0, marginRight: 11 }
|
||||
],
|
||||
{ writingDirection }
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
@@ -327,8 +348,11 @@ describe('StyleSheet', () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(StyleSheet([inlineStyle, { marginEnd: null, marginLeft: 11 }], { writingDirection }))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(
|
||||
StyleSheet([inlineStyle, { marginEnd: null, marginLeft: 11 }], {
|
||||
writingDirection
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
"",
|
||||
{
|
||||
@@ -347,7 +371,8 @@ describe('StyleSheet', () => {
|
||||
null,
|
||||
]
|
||||
`);
|
||||
expect(StyleSheet(staticStyle, { writingDirection })).toMatchInlineSnapshot(`
|
||||
expect(StyleSheet(staticStyle, { writingDirection }))
|
||||
.toMatchInlineSnapshot(`
|
||||
[
|
||||
"r-right-1bnbe1j r-textAlign-1ff274t r-marginLeft-1n0xq6e",
|
||||
null,
|
||||
@@ -356,7 +381,10 @@ describe('StyleSheet', () => {
|
||||
// logical wins
|
||||
expect(
|
||||
StyleSheet(
|
||||
[staticStyle, { marginLeft: 1, marginEnd: 0, marginStart: 0, marginRight: 11 }],
|
||||
[
|
||||
staticStyle,
|
||||
{ marginLeft: 1, marginEnd: 0, marginStart: 0, marginRight: 11 }
|
||||
],
|
||||
{
|
||||
writingDirection
|
||||
}
|
||||
@@ -371,8 +399,11 @@ describe('StyleSheet', () => {
|
||||
]
|
||||
`);
|
||||
// logical can be nulled
|
||||
expect(StyleSheet([staticStyle, { marginEnd: null, marginLeft: 11 }], { writingDirection }))
|
||||
.toMatchInlineSnapshot(`
|
||||
expect(
|
||||
StyleSheet([staticStyle, { marginEnd: null, marginLeft: 11 }], {
|
||||
writingDirection
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
"r-right-1bnbe1j r-textAlign-1ff274t",
|
||||
{
|
||||
|
||||
@@ -53,7 +53,9 @@ describe('StyleSheet/preprocess', () => {
|
||||
});
|
||||
|
||||
test('textShadowOffset only', () => {
|
||||
expect(preprocess({ textShadowOffset: { width: 1, height: 2 } })).toEqual({});
|
||||
expect(preprocess({ textShadowOffset: { width: 1, height: 2 } })).toEqual(
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
test('textShadowRadius only', () => {
|
||||
@@ -86,8 +88,12 @@ describe('StyleSheet/preprocess', () => {
|
||||
});
|
||||
|
||||
test('textShadowColor and textShadowRadius only', () => {
|
||||
expect(preprocess({ textShadowColor: 'red', textShadowRadius: 0 })).toEqual({});
|
||||
expect(preprocess({ textShadowColor: 'red', textShadowRadius: 5 })).toEqual({
|
||||
expect(
|
||||
preprocess({ textShadowColor: 'red', textShadowRadius: 0 })
|
||||
).toEqual({});
|
||||
expect(
|
||||
preprocess({ textShadowColor: 'red', textShadowRadius: 5 })
|
||||
).toEqual({
|
||||
textShadow: '0px 0px 5px rgba(255,0,0,1.00)'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,15 +46,30 @@ const SYSTEM_FONT_STACK =
|
||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif';
|
||||
|
||||
const STYLE_SHORT_FORM_EXPANSIONS = {
|
||||
borderColor: ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'],
|
||||
borderColor: [
|
||||
'borderTopColor',
|
||||
'borderRightColor',
|
||||
'borderBottomColor',
|
||||
'borderLeftColor'
|
||||
],
|
||||
borderRadius: [
|
||||
'borderTopLeftRadius',
|
||||
'borderTopRightRadius',
|
||||
'borderBottomRightRadius',
|
||||
'borderBottomLeftRadius'
|
||||
],
|
||||
borderStyle: ['borderTopStyle', 'borderRightStyle', 'borderBottomStyle', 'borderLeftStyle'],
|
||||
borderWidth: ['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'],
|
||||
borderStyle: [
|
||||
'borderTopStyle',
|
||||
'borderRightStyle',
|
||||
'borderBottomStyle',
|
||||
'borderLeftStyle'
|
||||
],
|
||||
borderWidth: [
|
||||
'borderTopWidth',
|
||||
'borderRightWidth',
|
||||
'borderBottomWidth',
|
||||
'borderLeftWidth'
|
||||
],
|
||||
marginHorizontal: ['marginRight', 'marginLeft'],
|
||||
marginVertical: ['marginTop', 'marginBottom'],
|
||||
overflow: ['overflowX', 'overflowY'],
|
||||
|
||||
@@ -28,11 +28,16 @@ function murmurhash2_32_gc(str, seed) {
|
||||
((str.charCodeAt(++i) & 0xff) << 16) |
|
||||
((str.charCodeAt(++i) & 0xff) << 24);
|
||||
|
||||
k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
k =
|
||||
(k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
k ^= k >>> 24;
|
||||
k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
k =
|
||||
(k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
|
||||
h = ((h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;
|
||||
h =
|
||||
((h & 0xffff) * 0x5bd1e995 +
|
||||
((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^
|
||||
k;
|
||||
|
||||
l -= 4;
|
||||
++i;
|
||||
@@ -45,7 +50,9 @@ function murmurhash2_32_gc(str, seed) {
|
||||
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
|
||||
case 1:
|
||||
h ^= str.charCodeAt(i) & 0xff;
|
||||
h = (h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
h =
|
||||
(h & 0xffff) * 0x5bd1e995 +
|
||||
((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16);
|
||||
}
|
||||
|
||||
h ^= h >>> 13;
|
||||
|
||||
@@ -208,7 +208,8 @@ export function classic(style: Style, name: string): CompilerOutput {
|
||||
const selector = `.${identifier}`;
|
||||
let animationName;
|
||||
if (animationKeyframes != null) {
|
||||
const [animationNames, keyframesRules] = processKeyframesValue(animationKeyframes);
|
||||
const [animationNames, keyframesRules] =
|
||||
processKeyframesValue(animationKeyframes);
|
||||
animationName = animationNames.join(',');
|
||||
compiledRules.push(...keyframesRules);
|
||||
}
|
||||
@@ -223,7 +224,10 @@ export function classic(style: Style, name: string): CompilerOutput {
|
||||
* Compile simple style object to inline DOM styles.
|
||||
* No support for 'animationKeyframes', 'placeholderTextColor', 'scrollbarWidth', or 'pointerEvents'.
|
||||
*/
|
||||
export function inline(originalStyle: Style, isRTL?: boolean): { [key: string]: mixed } {
|
||||
export function inline(
|
||||
originalStyle: Style,
|
||||
isRTL?: boolean
|
||||
): { [key: string]: mixed } {
|
||||
const style = originalStyle || emptyObject;
|
||||
const frozenProps = {};
|
||||
const nextStyle = {};
|
||||
@@ -233,7 +237,10 @@ export function inline(originalStyle: Style, isRTL?: boolean): { [key: string]:
|
||||
let prop = originalProp;
|
||||
let value = originalValue;
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(style, originalProp) || originalValue == null) {
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(style, originalProp) ||
|
||||
originalValue == null
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -253,12 +260,16 @@ export function inline(originalStyle: Style, isRTL?: boolean): { [key: string]:
|
||||
// BiDi flip transitionProperty value
|
||||
if (originalProp === 'transitionProperty') {
|
||||
// $FlowFixMe
|
||||
const originalValues = Array.isArray(originalValue) ? originalValue : [originalValue];
|
||||
const originalValues = Array.isArray(originalValue)
|
||||
? originalValue
|
||||
: [originalValue];
|
||||
originalValues.forEach((val, i) => {
|
||||
if (typeof val === 'string') {
|
||||
const valuePolyfill = PROPERTIES_I18N[val];
|
||||
if (valuePolyfill != null) {
|
||||
originalValues[i] = isRTL ? PROPERTIES_FLIP[valuePolyfill] : valuePolyfill;
|
||||
originalValues[i] = isRTL
|
||||
? PROPERTIES_FLIP[valuePolyfill]
|
||||
: valuePolyfill;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -281,7 +292,10 @@ export function inline(originalStyle: Style, isRTL?: boolean): { [key: string]:
|
||||
* Create a value string that normalizes different input values with a common
|
||||
* output.
|
||||
*/
|
||||
export function stringifyValueWithProperty(value: Value, property: ?string): string {
|
||||
export function stringifyValueWithProperty(
|
||||
value: Value,
|
||||
property: ?string
|
||||
): string {
|
||||
// e.g., 0 => '0px', 'black' => 'rgba(0,0,0,1)'
|
||||
const normalizedValue = normalizeValueWithProperty(value, property);
|
||||
return typeof normalizedValue !== 'string'
|
||||
@@ -302,7 +316,9 @@ function createAtomicRules(identifier: string, property, value): Rules {
|
||||
switch (property) {
|
||||
case 'animationKeyframes': {
|
||||
const [animationNames, keyframesRules] = processKeyframesValue(value);
|
||||
const block = createDeclarationBlock({ animationName: animationNames.join(',') });
|
||||
const block = createDeclarationBlock({
|
||||
animationName: animationNames.join(',')
|
||||
});
|
||||
rules.push(`${selector}${block}`, ...keyframesRules);
|
||||
break;
|
||||
}
|
||||
@@ -433,7 +449,9 @@ function processKeyframesValue(keyframesValue) {
|
||||
|
||||
const animationNames = [];
|
||||
const rules = [];
|
||||
const value = Array.isArray(keyframesValue) ? keyframesValue : [keyframesValue];
|
||||
const value = Array.isArray(keyframesValue)
|
||||
? keyframesValue
|
||||
: [keyframesValue];
|
||||
|
||||
value.forEach((keyframes) => {
|
||||
if (typeof keyframes === 'string') {
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
import isWebColor from '../../../modules/isWebColor';
|
||||
import processColor from '../../../exports/processColor';
|
||||
|
||||
const normalizeColor = (color?: number | string, opacity?: number = 1): void | string => {
|
||||
const normalizeColor = (
|
||||
color?: number | string,
|
||||
opacity?: number = 1
|
||||
): void | string => {
|
||||
if (color == null) return;
|
||||
|
||||
if (typeof color === 'string' && isWebColor(color)) {
|
||||
|
||||
@@ -23,9 +23,15 @@ const colorProps = {
|
||||
textShadowColor: true
|
||||
};
|
||||
|
||||
export default function normalizeValueWithProperty(value: any, property?: ?string): any {
|
||||
export default function normalizeValueWithProperty(
|
||||
value: any,
|
||||
property?: ?string
|
||||
): any {
|
||||
let returnValue = value;
|
||||
if ((property == null || !unitlessNumbers[property]) && typeof value === 'number') {
|
||||
if (
|
||||
(property == null || !unitlessNumbers[property]) &&
|
||||
typeof value === 'number'
|
||||
) {
|
||||
returnValue = `${value}px`;
|
||||
} else if (property != null && colorProps[property]) {
|
||||
returnValue = normalizeColor(value);
|
||||
|
||||
@@ -19,7 +19,12 @@ const resolveShadowValue = (style: Object): void | string => {
|
||||
const offsetY = normalizeValueWithProperty(height);
|
||||
const blurRadius = normalizeValueWithProperty(shadowRadius || 0);
|
||||
const color = normalizeColor(shadowColor || 'black', shadowOpacity);
|
||||
if (color != null && offsetX != null && offsetY != null && blurRadius != null) {
|
||||
if (
|
||||
color != null &&
|
||||
offsetX != null &&
|
||||
offsetY != null &&
|
||||
blurRadius != null
|
||||
) {
|
||||
return `${offsetX} ${offsetY} ${blurRadius} ${color}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,7 +32,9 @@ const slice = Array.prototype.slice;
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/CSSMediaRule
|
||||
* https://gist.github.com/necolas/aa0c37846ad6bd3b05b727b959e82674
|
||||
*/
|
||||
export default function createOrderedCSSStyleSheet(sheet: ?CSSStyleSheet): OrderedCSSStyleSheet {
|
||||
export default function createOrderedCSSStyleSheet(
|
||||
sheet: ?CSSStyleSheet
|
||||
): OrderedCSSStyleSheet {
|
||||
const groups: Groups = {};
|
||||
const selectors: Selectors = {};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user