mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f499de9031 | ||
|
|
318db8eedf | ||
|
|
071d223ee0 | ||
|
|
67bff8734f | ||
|
|
b25b65ba19 | ||
|
|
a4849cb3d6 | ||
|
|
385b9f4265 | ||
|
|
bfc8b3391e | ||
|
|
2df7552fa2 | ||
|
|
e1623b7525 | ||
|
|
fa8a25eb6b | ||
|
|
96c2be8567 | ||
|
|
53bc661138 | ||
|
|
69ecaef068 | ||
|
|
215b0a50cf | ||
|
|
11c214d0c9 | ||
|
|
dc88683798 | ||
|
|
1a9780f0e3 | ||
|
|
72bb2f4089 | ||
|
|
70a957452c | ||
|
|
a4310ede9c | ||
|
|
0580e88aa5 | ||
|
|
762389f775 | ||
|
|
4bced9099a | ||
|
|
21cc745d51 | ||
|
|
9147b0753a | ||
|
|
2480de6ffb | ||
|
|
b6f2b148f4 | ||
|
|
60a4d22307 | ||
|
|
09f6d165ec | ||
|
|
88c9a42fca | ||
|
|
28ced2e558 | ||
|
|
b8095f4692 | ||
|
|
44b04b6d42 | ||
|
|
fa03840e68 | ||
|
|
490db92562 | ||
|
|
e996b3f346 | ||
|
|
f791fb9e66 | ||
|
|
b886bc4db9 | ||
|
|
91e217ff54 | ||
|
|
5ff59b448b | ||
|
|
de30f408e5 | ||
|
|
212a743fdf | ||
|
|
b27bd00a38 | ||
|
|
2aa79979d3 | ||
|
|
2fcf7b1f49 | ||
|
|
7ccc5934d0 | ||
|
|
bc9e4db9e9 |
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
declare module 'jest-diff' {
|
||||
import type {CompareKeys} from 'pretty-format';
|
||||
|
||||
declare export type DiffOptionsColor = (arg: string) => string; // subset of Chalk type
|
||||
|
||||
declare export type DiffOptions = {
|
||||
aAnnotation?: string,
|
||||
aColor?: DiffOptionsColor,
|
||||
aIndicator?: string,
|
||||
bAnnotation?: string,
|
||||
bColor?: DiffOptionsColor,
|
||||
bIndicator?: string,
|
||||
changeColor?: DiffOptionsColor,
|
||||
changeLineTrailingSpaceColor?: DiffOptionsColor,
|
||||
commonColor?: DiffOptionsColor,
|
||||
commonIndicator?: string,
|
||||
commonLineTrailingSpaceColor?: DiffOptionsColor,
|
||||
contextLines?: number,
|
||||
emptyFirstOrLastLinePlaceholder?: string,
|
||||
expand?: boolean,
|
||||
includeChangeCounts?: boolean,
|
||||
omitAnnotationLines?: boolean,
|
||||
patchColor?: DiffOptionsColor,
|
||||
compareKeys?: CompareKeys,
|
||||
};
|
||||
|
||||
declare export function diff(
|
||||
a: mixed,
|
||||
b: mixed,
|
||||
options?: DiffOptions,
|
||||
): string | null;
|
||||
}
|
||||
+4
-1
@@ -19,7 +19,6 @@ declare type Colors = {
|
||||
tag: {close: string, open: string},
|
||||
value: {close: string, open: string},
|
||||
};
|
||||
declare type CompareKeys = ((a: string, b: string) => number) | null | void;
|
||||
|
||||
declare type PrettyFormatPlugin =
|
||||
| {
|
||||
@@ -38,6 +37,10 @@ declare type PrettyFormatPlugin =
|
||||
};
|
||||
|
||||
declare module 'pretty-format' {
|
||||
declare export type CompareKeys =
|
||||
| ((a: string, b: string) => number)
|
||||
| null
|
||||
| void;
|
||||
declare export function format(
|
||||
value: mixed,
|
||||
options?: ?{
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -25,4 +25,5 @@ module.exports = {
|
||||
transformIgnorePatterns: ['.*'],
|
||||
testRunner: './jest/integration/runner/index.js',
|
||||
watchPathIgnorePatterns: ['<rootDir>/jest/integration/build/'],
|
||||
globalSetup: './jest/integration/runner/warmup/index.js',
|
||||
};
|
||||
|
||||
@@ -12,25 +12,29 @@
|
||||
import type {TestSuiteResult} from '../runtime/setup';
|
||||
|
||||
import entrypointTemplate from './entrypoint-template';
|
||||
import {spawnSync} from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
import {
|
||||
getBuckModeForPlatform,
|
||||
getDebugInfoFromCommandResult,
|
||||
getFantomTestConfig,
|
||||
getShortHash,
|
||||
runBuck2,
|
||||
symbolicateStackTrace,
|
||||
} from './utils';
|
||||
import fs from 'fs';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {formatResultsErrors} from 'jest-message-util';
|
||||
import Metro from 'metro';
|
||||
import nullthrows from 'nullthrows';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const BUILD_OUTPUT_PATH = path.resolve(__dirname, '..', 'build');
|
||||
|
||||
const ENABLE_OPTIMIZED_MODE: false = false;
|
||||
const PRINT_FANTOM_OUTPUT: false = false;
|
||||
|
||||
function parseRNTesterCommandResult(
|
||||
commandArgs: $ReadOnlyArray<string>,
|
||||
result: ReturnType<typeof spawnSync>,
|
||||
): {logs: string, testResult: TestSuiteResult} {
|
||||
function parseRNTesterCommandResult(result: ReturnType<typeof runBuck2>): {
|
||||
logs: string,
|
||||
testResult: TestSuiteResult,
|
||||
} {
|
||||
const stdout = result.stdout.toString();
|
||||
|
||||
const outputArray = stdout
|
||||
@@ -46,51 +50,26 @@ function parseRNTesterCommandResult(
|
||||
testResult = JSON.parse(nullthrows(testResultJSON));
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
[
|
||||
'Failed to parse test results from RN tester binary result. Full output:',
|
||||
'buck2 ' + commandArgs.join(' '),
|
||||
'stdout:',
|
||||
stdout,
|
||||
'stderr:',
|
||||
result.stderr.toString(),
|
||||
].join('\n'),
|
||||
'Failed to parse test results from RN tester binary result.\n' +
|
||||
getDebugInfoFromCommandResult(result),
|
||||
);
|
||||
}
|
||||
|
||||
return {logs: outputArray.join('\n'), testResult};
|
||||
}
|
||||
|
||||
function getBuckModeForPlatform() {
|
||||
const mode = ENABLE_OPTIMIZED_MODE ? 'opt' : 'dev';
|
||||
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
return `@//arvr/mode/linux/${mode}`;
|
||||
case 'darwin':
|
||||
return os.arch() === 'arm64'
|
||||
? `@//arvr/mode/mac-arm/${mode}`
|
||||
: `@//arvr/mode/mac/${mode}`;
|
||||
case 'win32':
|
||||
return `@//arvr/mode/win/${mode}`;
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getShortHash(contents: string): string {
|
||||
return crypto.createHash('md5').update(contents).digest('hex').slice(0, 8);
|
||||
}
|
||||
|
||||
function generateBytecodeBundle({
|
||||
sourcePath,
|
||||
bytecodePath,
|
||||
isOptimizedMode,
|
||||
}: {
|
||||
sourcePath: string,
|
||||
bytecodePath: string,
|
||||
isOptimizedMode: boolean,
|
||||
}): void {
|
||||
const hermesCompilerCommandArgs = [
|
||||
const hermesCompilerCommandResult = runBuck2([
|
||||
'run',
|
||||
getBuckModeForPlatform(),
|
||||
getBuckModeForPlatform(isOptimizedMode),
|
||||
'//xplat/hermes/tools/hermesc:hermesc',
|
||||
'--',
|
||||
'-emit-binary',
|
||||
@@ -100,33 +79,10 @@ function generateBytecodeBundle({
|
||||
'-out',
|
||||
bytecodePath,
|
||||
sourcePath,
|
||||
];
|
||||
|
||||
const hermesCompilerCommandResult = spawnSync(
|
||||
'buck2',
|
||||
hermesCompilerCommandArgs,
|
||||
{
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
]);
|
||||
|
||||
if (hermesCompilerCommandResult.status !== 0) {
|
||||
throw new Error(
|
||||
[
|
||||
'Failed to run Hermes compiler. Full output:',
|
||||
'buck2 ' + hermesCompilerCommandArgs.join(' '),
|
||||
'stdout:',
|
||||
hermesCompilerCommandResult.stdout,
|
||||
'stderr:',
|
||||
hermesCompilerCommandResult.stderr,
|
||||
'error:',
|
||||
hermesCompilerCommandResult.error,
|
||||
].join('\n'),
|
||||
);
|
||||
throw new Error(getDebugInfoFromCommandResult(hermesCompilerCommandResult));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +95,9 @@ module.exports = async function runTest(
|
||||
): mixed {
|
||||
const startTime = Date.now();
|
||||
|
||||
const isOptimizedMode = ENABLE_OPTIMIZED_MODE;
|
||||
const testConfig = getFantomTestConfig(testPath);
|
||||
|
||||
const isOptimizedMode = testConfig.mode === 'opt';
|
||||
|
||||
const metroConfig = await Metro.loadConfig({
|
||||
config: path.resolve(__dirname, '..', 'config', 'metro.config.js'),
|
||||
@@ -163,76 +121,54 @@ module.exports = async function runTest(
|
||||
fs.mkdirSync(path.dirname(entrypointPath), {recursive: true});
|
||||
fs.writeFileSync(entrypointPath, entrypointContents, 'utf8');
|
||||
|
||||
const sourceMapPath = path.join(
|
||||
path.dirname(testJSBundlePath),
|
||||
path.basename(testJSBundlePath, '.js') + '.map',
|
||||
);
|
||||
|
||||
await Metro.runBuild(metroConfig, {
|
||||
entry: entrypointPath,
|
||||
out: testJSBundlePath,
|
||||
platform: 'android',
|
||||
minify: isOptimizedMode,
|
||||
dev: !isOptimizedMode,
|
||||
sourceMap: true,
|
||||
sourceMapUrl: sourceMapPath,
|
||||
});
|
||||
|
||||
if (isOptimizedMode) {
|
||||
generateBytecodeBundle({
|
||||
sourcePath: testJSBundlePath,
|
||||
bytecodePath: testBytecodeBundlePath,
|
||||
isOptimizedMode,
|
||||
});
|
||||
}
|
||||
|
||||
const rnTesterCommandArgs = [
|
||||
const rnTesterCommandResult = runBuck2([
|
||||
'run',
|
||||
getBuckModeForPlatform(),
|
||||
getBuckModeForPlatform(isOptimizedMode),
|
||||
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
|
||||
'--',
|
||||
'--bundlePath',
|
||||
testBundlePath,
|
||||
];
|
||||
const rnTesterCommandResult = spawnSync('buck2', rnTesterCommandArgs, {
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
|
||||
},
|
||||
});
|
||||
]);
|
||||
|
||||
if (rnTesterCommandResult.status !== 0) {
|
||||
throw new Error(
|
||||
[
|
||||
'Failed to run test in RN tester binary. Full output:',
|
||||
'buck2 ' + rnTesterCommandArgs.join(' '),
|
||||
'stdout:',
|
||||
rnTesterCommandResult.stdout,
|
||||
'stderr:',
|
||||
rnTesterCommandResult.stderr,
|
||||
'error:',
|
||||
rnTesterCommandResult.error,
|
||||
].join('\n'),
|
||||
);
|
||||
throw new Error(getDebugInfoFromCommandResult(rnTesterCommandResult));
|
||||
}
|
||||
|
||||
if (PRINT_FANTOM_OUTPUT) {
|
||||
console.log(
|
||||
[
|
||||
'RN tester binary. Full output:',
|
||||
'buck2 ' + rnTesterCommandArgs.join(' '),
|
||||
'stdout:',
|
||||
rnTesterCommandResult.stdout,
|
||||
'stderr:',
|
||||
rnTesterCommandResult.stderr,
|
||||
'error:',
|
||||
rnTesterCommandResult.error,
|
||||
].join('\n'),
|
||||
);
|
||||
console.log(getDebugInfoFromCommandResult(rnTesterCommandResult));
|
||||
}
|
||||
|
||||
const rnTesterParsedOutput = parseRNTesterCommandResult(
|
||||
rnTesterCommandArgs,
|
||||
rnTesterCommandResult,
|
||||
);
|
||||
|
||||
const testResultError = rnTesterParsedOutput.testResult.error;
|
||||
if (testResultError) {
|
||||
const error = new Error(testResultError.message);
|
||||
error.stack = testResultError.stack;
|
||||
error.stack = symbolicateStackTrace(sourceMapPath, testResultError.stack);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -248,6 +184,9 @@ module.exports = async function runTest(
|
||||
failureDetails: [] as Array<string>,
|
||||
testFilePath: testPath,
|
||||
...testResult,
|
||||
failureMessages: testResult.failureMessages.map(maybeStackTrace =>
|
||||
symbolicateStackTrace(sourceMapPath, maybeStackTrace),
|
||||
),
|
||||
})) ?? [];
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {spawnSync} from 'child_process';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {extract, parse} from 'jest-docblock';
|
||||
import os from 'os';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import {SourceMapConsumer} from 'source-map';
|
||||
|
||||
type DocblockPragmas = {[key: string]: string | string[]};
|
||||
type FantomTestMode = 'dev' | 'opt';
|
||||
type FantomTestConfig = {
|
||||
mode: FantomTestMode,
|
||||
};
|
||||
|
||||
const DEFAULT_MODE: FantomTestMode = 'dev';
|
||||
|
||||
/**
|
||||
* Extracts the Fantom configuration from the test file, specified as part of
|
||||
* the docblock comment. E.g.:
|
||||
*
|
||||
* ```
|
||||
* /**
|
||||
* * @flow strict-local
|
||||
* * @fantom mode:opt
|
||||
* *
|
||||
* ```
|
||||
*
|
||||
* So far the only supported option is `mode`, which can be 'dev' or 'opt'.
|
||||
*/
|
||||
export function getFantomTestConfig(testPath: string): FantomTestConfig {
|
||||
const docblock = extract(fs.readFileSync(testPath, 'utf8'));
|
||||
const pragmas = parse(docblock) as DocblockPragmas;
|
||||
|
||||
const config = {
|
||||
mode: DEFAULT_MODE,
|
||||
};
|
||||
|
||||
const maybeMode = pragmas.fantom_mode;
|
||||
|
||||
if (maybeMode != null) {
|
||||
if (Array.isArray(maybeMode)) {
|
||||
throw new Error('Expected a single value for @fantom_mode');
|
||||
}
|
||||
|
||||
const mode = maybeMode;
|
||||
|
||||
if (mode === 'dev' || mode === 'opt') {
|
||||
config.mode = mode;
|
||||
} else {
|
||||
throw new Error(`Invalid Fantom mode: ${mode}`);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
export function getBuckModeForPlatform(enableRelease: boolean = false): string {
|
||||
const mode = enableRelease ? 'opt' : 'dev';
|
||||
|
||||
switch (os.platform()) {
|
||||
case 'linux':
|
||||
return `@//arvr/mode/linux/${mode}`;
|
||||
case 'darwin':
|
||||
return os.arch() === 'arm64'
|
||||
? `@//arvr/mode/mac-arm/${mode}`
|
||||
: `@//arvr/mode/mac/${mode}`;
|
||||
case 'win32':
|
||||
return `@//arvr/mode/win/${mode}`;
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${os.platform()}`);
|
||||
}
|
||||
}
|
||||
|
||||
type SpawnResultWithOriginalCommand = {
|
||||
...ReturnType<typeof spawnSync>,
|
||||
originalCommand: string,
|
||||
...
|
||||
};
|
||||
|
||||
export function runBuck2(args: Array<string>): SpawnResultWithOriginalCommand {
|
||||
const result = spawnSync('buck2', args, {
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...result,
|
||||
originalCommand: `buck2 ${args.join(' ')}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDebugInfoFromCommandResult(
|
||||
commandResult: SpawnResultWithOriginalCommand,
|
||||
): string {
|
||||
const logLines = [
|
||||
`Command ${commandResult.status === 0 ? 'succeeded' : 'failed'}: ${commandResult.originalCommand}`,
|
||||
'',
|
||||
'stdout:',
|
||||
commandResult.stdout,
|
||||
'',
|
||||
'stderr:',
|
||||
commandResult.stderr,
|
||||
];
|
||||
|
||||
if (commandResult.error) {
|
||||
logLines.push('', 'error:', String(commandResult.error));
|
||||
}
|
||||
|
||||
return logLines.join('\n');
|
||||
}
|
||||
|
||||
export function getShortHash(contents: string): string {
|
||||
return crypto.createHash('md5').update(contents).digest('hex').slice(0, 8);
|
||||
}
|
||||
|
||||
export function symbolicateStackTrace(
|
||||
sourceMapPath: string,
|
||||
stackTrace: string,
|
||||
): string {
|
||||
const sourceMapData = JSON.parse(fs.readFileSync(sourceMapPath, 'utf8'));
|
||||
const consumer = new SourceMapConsumer(sourceMapData);
|
||||
|
||||
return stackTrace
|
||||
.split('\n')
|
||||
.map(line => {
|
||||
const match = line.match(/at (.*) \((.*):(\d+):(\d+)\)/);
|
||||
if (match) {
|
||||
const functionName = match[1];
|
||||
// const fileName = match[2];
|
||||
const lineNumber = parseInt(match[3], 10);
|
||||
const columnNumber = parseInt(match[4], 10);
|
||||
// Get the original position
|
||||
const originalPosition = consumer.originalPositionFor({
|
||||
line: lineNumber,
|
||||
column: columnNumber,
|
||||
});
|
||||
return `at ${originalPosition.name ?? functionName} (${originalPosition.source}:${originalPosition.line}:${originalPosition.column})`;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
require('../../../../scripts/build/babel-register').registerForMonorepo();
|
||||
|
||||
module.exports = require('./warmup');
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {
|
||||
getBuckModeForPlatform,
|
||||
getDebugInfoFromCommandResult,
|
||||
runBuck2,
|
||||
} from '../utils';
|
||||
// $FlowExpectedError[untyped-import]
|
||||
import fs from 'fs';
|
||||
import Metro from 'metro';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
export default async function warmUp(
|
||||
globalConfig: {...},
|
||||
projectConfig: {...},
|
||||
): Promise<void> {
|
||||
try {
|
||||
warmUpHermesCompiler();
|
||||
warmUpRNTesterCLI();
|
||||
await warmUpMetro();
|
||||
} catch (e) {
|
||||
// Sandcastle fails to parse the test output if we log stuff to stdout/stderr.
|
||||
if ((process.env.SANDCASTLE ?? '') !== '') {
|
||||
console.error(
|
||||
'Global warmup failed. Tests will continue to run but will likely fail. Details:\n',
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function warmUpMetro(): Promise<void> {
|
||||
const metroConfig = await Metro.loadConfig({
|
||||
config: path.resolve(__dirname, '..', '..', 'config', 'metro.config.js'),
|
||||
});
|
||||
|
||||
const entrypointPath = path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'runtime',
|
||||
'WarmUpEntryPoint.js',
|
||||
);
|
||||
|
||||
const bundlePath = path.join(
|
||||
os.tmpdir(),
|
||||
`fantom-warmup-bundle-${Date.now()}.js`,
|
||||
);
|
||||
|
||||
await Metro.runBuild(metroConfig, {
|
||||
entry: entrypointPath,
|
||||
out: bundlePath,
|
||||
platform: 'android',
|
||||
minify: false,
|
||||
dev: true,
|
||||
});
|
||||
|
||||
try {
|
||||
fs.unlinkSync(bundlePath);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function warmUpHermesCompiler(): void {
|
||||
const buildHermesCompilerCommandResult = runBuck2([
|
||||
'build',
|
||||
getBuckModeForPlatform(),
|
||||
'//xplat/hermes/tools/hermesc:hermesc',
|
||||
]);
|
||||
|
||||
if (buildHermesCompilerCommandResult.status !== 0) {
|
||||
throw new Error(
|
||||
getDebugInfoFromCommandResult(buildHermesCompilerCommandResult),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function warmUpRNTesterCLI(): void {
|
||||
const buildRNTesterCommandResult = runBuck2([
|
||||
'build',
|
||||
getBuckModeForPlatform(),
|
||||
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
|
||||
]);
|
||||
|
||||
if (buildRNTesterCommandResult.status !== 0) {
|
||||
throw new Error(getDebugInfoFromCommandResult(buildRNTesterCommandResult));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is just an entrypoint to warm up the Metro cache before the tests run.
|
||||
*/
|
||||
|
||||
import 'react-native/Libraries/Core/InitializeCore.js';
|
||||
import 'react-native/src/private/__tests__/ReactNativeTester';
|
||||
import './setup';
|
||||
@@ -194,7 +194,10 @@ class ErrorWithCustomBlame extends Error {
|
||||
this.#cachedProcessedStack = originalStack;
|
||||
} else {
|
||||
const lines = originalStack.split('\n');
|
||||
lines.splice(1, this.#ignoredFrameCount);
|
||||
const index = lines.findIndex(line =>
|
||||
/at (.*) \((.*):(\d+):(\d+)\)/.test(line),
|
||||
);
|
||||
lines.splice(index > -1 ? index : 1, this.#ignoredFrameCount);
|
||||
this.#cachedProcessedStack = lines.join('\n');
|
||||
}
|
||||
}
|
||||
@@ -307,6 +310,48 @@ class Expect {
|
||||
}
|
||||
}
|
||||
|
||||
toBeGreaterThanOrEqual(expected: number): void {
|
||||
if (typeof this.#received !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)} to be a number but it was a ${typeof this.#received}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
if (typeof expected !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(expected)} to be a number but it was a ${typeof expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
const pass = this.#received >= expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be greater than or equal to ${expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
toBeLessThanOrEqual(expected: number): void {
|
||||
if (typeof this.#received !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)} to be a number but it was a ${typeof this.#received}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
if (typeof expected !== 'number') {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(expected)} to be a number but it was a ${typeof expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
|
||||
const pass = this.#received <= expected;
|
||||
if (!this.#isExpectedResult(pass)) {
|
||||
throw new ErrorWithCustomBlame(
|
||||
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be less than or equal to ${expected}`,
|
||||
).blameToPreviousFrame();
|
||||
}
|
||||
}
|
||||
|
||||
#isExpectedResult(pass: boolean): boolean {
|
||||
return this.#isNot ? !pass : pass;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
"hermes-transform": "0.25.1",
|
||||
"inquirer": "^7.1.0",
|
||||
"jest": "^29.6.3",
|
||||
"jest-diff": "^29.7.0",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jscodeshift": "^0.14.0",
|
||||
"metro-babel-register": "^0.81.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<6b92b66e59525cef52902139f863f175>>
|
||||
Git revision: b61aae3ccc6e2684dfbf1e2a06b0f985b459f11f
|
||||
@generated SignedSource<<cecad43da3fd917e15322ee3efbed875>>
|
||||
Git revision: 486803f6bf272e0629297265dee8048a2f1269dd
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebookexperimental/rn-chrome-devtools-frontend
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -42,7 +42,7 @@ import*as e from"../../ui/legacy/legacy.js";import*as t from"../../core/host/hos
|
||||
<p>${d(a.docsDebuggingBasicsDetail)}</p>
|
||||
</div>
|
||||
</button>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/react-devtools")} title=${d(a.docsReactNativeDevTools)}>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/react-native-devtools")} title=${d(a.docsReactNativeDevTools)}>
|
||||
<div class="rn-welcome-image" style="background-image: url('${c}')"></div>
|
||||
<div>
|
||||
<p class="devtools-link">${d(a.docsReactNativeDevTools)}</p>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+7
-3
@@ -12,6 +12,7 @@ import com.facebook.react.utils.detectOSAwareHermesCommand
|
||||
import com.facebook.react.utils.moveTo
|
||||
import com.facebook.react.utils.windowsAwareCommandLine
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileTree
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
@@ -19,6 +20,7 @@ import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
abstract class BundleHermesCTask : DefaultTask() {
|
||||
|
||||
@@ -26,6 +28,8 @@ abstract class BundleHermesCTask : DefaultTask() {
|
||||
group = "react"
|
||||
}
|
||||
|
||||
@get:Inject abstract val execOperations: ExecOperations
|
||||
|
||||
@get:Internal abstract val root: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
@@ -127,9 +131,9 @@ abstract class BundleHermesCTask : DefaultTask() {
|
||||
File(jsIntermediateSourceMapsDir.get().asFile, "$bundleAssetName.compiler.map")
|
||||
|
||||
private fun runCommand(command: List<Any>) {
|
||||
project.exec {
|
||||
it.workingDir(root.get().asFile)
|
||||
it.commandLine(command)
|
||||
execOperations.exec { exec ->
|
||||
exec.workingDir(root.get().asFile)
|
||||
exec.commandLine(command)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+1
-1
@@ -327,7 +327,7 @@ export interface NativeModuleBooleanTypeAnnotation {
|
||||
|
||||
export type NativeModuleEnumMember = {
|
||||
readonly name: string;
|
||||
readonly value: string | number;
|
||||
readonly value: NativeModuleStringLiteralTypeAnnotation | NativeModuleNumberLiteralTypeAnnotation,
|
||||
};
|
||||
|
||||
export type NativeModuleEnumMemberType =
|
||||
|
||||
+1
-1
@@ -311,7 +311,7 @@ export type NativeModuleNumberTypeAnnotation = $ReadOnly<{
|
||||
|
||||
export type NativeModuleEnumMember = {
|
||||
name: string,
|
||||
value: string | number,
|
||||
value: StringLiteralTypeAnnotation | NumberLiteralTypeAnnotation,
|
||||
};
|
||||
|
||||
export type NativeModuleEnumMemberType =
|
||||
|
||||
@@ -96,7 +96,7 @@ function combineSchemasInFileListAndWriteToFile(
|
||||
exclude: ?RegExp,
|
||||
): void {
|
||||
const combined = combineSchemasInFileList(fileList, platform, exclude);
|
||||
const formattedSchema = JSON.stringify(combined, null, 2);
|
||||
const formattedSchema = JSON.stringify(combined);
|
||||
fs.writeFileSync(outfile, formattedSchema);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,4 +84,4 @@ for (const file of schemaFiles) {
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(output, JSON.stringify({modules}, null, 2));
|
||||
fs.writeFileSync(output, JSON.stringify({modules}));
|
||||
|
||||
@@ -406,6 +406,14 @@ struct Bridging<${enumName}> {
|
||||
};`;
|
||||
};
|
||||
|
||||
function getMemberValueAppearance(member: NativeModuleEnumMember['value']) {
|
||||
if (member.type === 'StringLiteralTypeAnnotation') {
|
||||
return `"${member.value}"`;
|
||||
} else {
|
||||
return member.value;
|
||||
}
|
||||
}
|
||||
|
||||
function generateEnum(
|
||||
hasteModuleName: string,
|
||||
origEnumName: string,
|
||||
@@ -417,9 +425,6 @@ function generateEnum(
|
||||
const nativeEnumMemberType: NativeEnumMemberValueType =
|
||||
memberType === 'StringTypeAnnotation' ? 'std::string' : 'int32_t';
|
||||
|
||||
const getMemberValueAppearance = (value: string | number) =>
|
||||
memberType === 'StringTypeAnnotation' ? `"${value}"` : `${value}`;
|
||||
|
||||
const fromCases =
|
||||
members
|
||||
.map(
|
||||
|
||||
+60
-15
@@ -163,11 +163,17 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'ONE',
|
||||
value: '1',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TWO',
|
||||
value: '2',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -178,15 +184,24 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'POINT_ZERO',
|
||||
value: '0.0',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'POINT_ONE',
|
||||
value: '0.1',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'POINT_TWO',
|
||||
value: '0.2',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0.2,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -197,11 +212,17 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'HELLO',
|
||||
value: 'hello',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'hello',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'GoodBye',
|
||||
value: 'goodbye',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'goodbye',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1926,11 +1947,17 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'IA',
|
||||
value: '23',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 23,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'IB',
|
||||
value: '42',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 42,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1941,11 +1968,17 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'FA',
|
||||
value: '1.23',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1.23,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'FB',
|
||||
value: '4.56',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 4.56,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1956,11 +1989,17 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'NA',
|
||||
value: 'NA',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'NA',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'NB',
|
||||
value: 'NB',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'NB',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1971,11 +2010,17 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = {
|
||||
members: [
|
||||
{
|
||||
name: 'SA',
|
||||
value: 's---a',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 's---a',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SB',
|
||||
value: 's---b',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 's---b',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+2
-2
@@ -2047,7 +2047,7 @@ template <>
|
||||
struct Bridging<NativeSampleTurboModuleFloatEnum> {
|
||||
static NativeSampleTurboModuleFloatEnum fromJs(jsi::Runtime &rt, const jsi::Value &rawValue) {
|
||||
double value = (double)rawValue.asNumber();
|
||||
if (value == 0.0) {
|
||||
if (value == 0) {
|
||||
return NativeSampleTurboModuleFloatEnum::POINT_ZERO;
|
||||
} else if (value == 0.1) {
|
||||
return NativeSampleTurboModuleFloatEnum::POINT_ONE;
|
||||
@@ -2060,7 +2060,7 @@ struct Bridging<NativeSampleTurboModuleFloatEnum> {
|
||||
|
||||
static jsi::Value toJs(jsi::Runtime &rt, NativeSampleTurboModuleFloatEnum value) {
|
||||
if (value == NativeSampleTurboModuleFloatEnum::POINT_ZERO) {
|
||||
return bridging::toJs(rt, 0.0);
|
||||
return bridging::toJs(rt, 0);
|
||||
} else if (value == NativeSampleTurboModuleFloatEnum::POINT_ONE) {
|
||||
return bridging::toJs(rt, 0.1);
|
||||
} else if (value == NativeSampleTurboModuleFloatEnum::POINT_TWO) {
|
||||
|
||||
+16
-4
@@ -478,11 +478,17 @@ describe('typeEnumResolution', () => {
|
||||
members: [
|
||||
{
|
||||
name: 'Hello',
|
||||
value: 'hello',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'hello',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Goodbye',
|
||||
value: 'goodbye',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'goodbye',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -521,11 +527,17 @@ describe('typeEnumResolution', () => {
|
||||
members: [
|
||||
{
|
||||
name: 'On',
|
||||
value: '1',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Off',
|
||||
value: '0',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+60
-15
@@ -147,11 +147,17 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': 'SD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': 'HD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -162,15 +168,24 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'Corrupted',
|
||||
'value': -1
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': -1
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': 1080
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -181,15 +196,24 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': 'one'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': 'two'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': 'three'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -471,11 +495,17 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': 'SD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': 'HD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -486,11 +516,17 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': 1080
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -501,15 +537,24 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`]
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': 'one'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': 'two'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': 'three'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+22
-4
@@ -230,10 +230,28 @@ class FlowParser implements Parser {
|
||||
parseEnumMembers(
|
||||
typeAnnotation: $FlowFixMe,
|
||||
): $ReadOnlyArray<NativeModuleEnumMember> {
|
||||
return typeAnnotation.members.map(member => ({
|
||||
name: member.id.name,
|
||||
value: member.init?.value ?? member.id.name,
|
||||
}));
|
||||
return typeAnnotation.members.map(member => {
|
||||
const value =
|
||||
typeof member.init?.value === 'number'
|
||||
? {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: member.init.value,
|
||||
}
|
||||
: typeof member.init?.value === 'string'
|
||||
? {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: member.init.value,
|
||||
}
|
||||
: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: member.id.name,
|
||||
};
|
||||
|
||||
return {
|
||||
name: member.id.name,
|
||||
value: value,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
isModuleInterface(node: $FlowFixMe): boolean {
|
||||
|
||||
+16
-4
@@ -175,21 +175,33 @@ export class MockedParser implements Parser {
|
||||
? [
|
||||
{
|
||||
name: 'Hello',
|
||||
value: 'hello',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'hello',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Goodbye',
|
||||
value: 'goodbye',
|
||||
value: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: 'goodbye',
|
||||
},
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: 'On',
|
||||
value: '1',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Off',
|
||||
value: '0',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
+60
-15
@@ -134,11 +134,17 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': 'SD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': 'HD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -149,15 +155,24 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'Corrupted',
|
||||
'value': -1
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': -1
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': 1080
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -168,15 +183,24 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': 'one'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': 'two'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': 'three'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -458,11 +482,17 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'SD',
|
||||
'value': 'SD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'SD'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'HD',
|
||||
'value': 'HD'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'HD'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -473,11 +503,17 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'Low',
|
||||
'value': 720
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 720
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'High',
|
||||
'value': 1080
|
||||
'value': {
|
||||
'type': 'NumberLiteralTypeAnnotation',
|
||||
'value': 1080
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -488,15 +524,24 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL
|
||||
'members': [
|
||||
{
|
||||
'name': 'One',
|
||||
'value': 'one'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'one'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Two',
|
||||
'value': 'two'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'two'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Three',
|
||||
'value': 'three'
|
||||
'value': {
|
||||
'type': 'StringLiteralTypeAnnotation',
|
||||
'value': 'three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+35
-5
@@ -124,9 +124,27 @@ describe('TypeScript Module Parser', () => {
|
||||
|
||||
expect(parser).not.toThrow();
|
||||
expect(parser().enumMap.MyEnum.members).toEqual([
|
||||
{name: 'ZERO', value: 0},
|
||||
{name: 'POSITIVE', value: 1},
|
||||
{name: 'NEGATIVE', value: -1},
|
||||
{
|
||||
name: 'ZERO',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'POSITIVE',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'NEGATIVE',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: -1,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -147,8 +165,20 @@ describe('TypeScript Module Parser', () => {
|
||||
|
||||
expect(parser).not.toThrow();
|
||||
expect(parser().enumMap.MyEnum.members).toEqual([
|
||||
{name: 'ZERO', value: 0},
|
||||
{name: 'POSITIVE', value: 1},
|
||||
{
|
||||
name: 'ZERO',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'POSITIVE',
|
||||
value: {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -250,17 +250,30 @@ class TypeScriptParser implements Parser {
|
||||
typeAnnotation: $FlowFixMe,
|
||||
): $ReadOnlyArray<NativeModuleEnumMember> {
|
||||
return typeAnnotation.members.map(member => {
|
||||
// Handle negative values
|
||||
if (member.initializer?.operator === '-') {
|
||||
return {
|
||||
name: member.id.name,
|
||||
value: -member.initializer?.argument?.value ?? member.id.name,
|
||||
};
|
||||
}
|
||||
const value =
|
||||
member.initializer?.operator === '-'
|
||||
? {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: -1 * member.initializer?.argument?.value,
|
||||
}
|
||||
: typeof member.initializer?.value === 'number'
|
||||
? {
|
||||
type: 'NumberLiteralTypeAnnotation',
|
||||
value: member.initializer?.value,
|
||||
}
|
||||
: typeof member.initializer?.value === 'string'
|
||||
? {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: member.initializer?.value,
|
||||
}
|
||||
: {
|
||||
type: 'StringLiteralTypeAnnotation',
|
||||
value: member.id.name,
|
||||
};
|
||||
|
||||
return {
|
||||
name: member.id.name,
|
||||
value: member.initializer?.value ?? member.id.name,
|
||||
value,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -106,17 +106,17 @@ export function allowTransformProp(prop: string): void {
|
||||
}
|
||||
|
||||
export function isSupportedColorStyleProp(prop: string): boolean {
|
||||
return Object.hasOwn(SUPPORTED_COLOR_STYLES, prop);
|
||||
return SUPPORTED_COLOR_STYLES.hasOwnProperty(prop);
|
||||
}
|
||||
|
||||
export function isSupportedInterpolationParam(param: string): boolean {
|
||||
return Object.hasOwn(SUPPORTED_INTERPOLATION_PARAMS, param);
|
||||
return SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(param);
|
||||
}
|
||||
|
||||
export function isSupportedStyleProp(prop: string): boolean {
|
||||
return Object.hasOwn(SUPPORTED_STYLES, prop);
|
||||
return SUPPORTED_STYLES.hasOwnProperty(prop);
|
||||
}
|
||||
|
||||
export function isSupportedTransformProp(prop: string): boolean {
|
||||
return Object.hasOwn(SUPPORTED_TRANSFORMS, prop);
|
||||
return SUPPORTED_TRANSFORMS.hasOwnProperty(prop);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ function createAnimatedProps(
|
||||
const key = keys[ii];
|
||||
const value = inputProps[key];
|
||||
|
||||
if (allowlist == null || Object.hasOwn(allowlist, key)) {
|
||||
if (allowlist == null || hasOwn(allowlist, key)) {
|
||||
let node;
|
||||
if (key === 'style') {
|
||||
node = AnimatedStyle.from(value, allowlist?.style);
|
||||
@@ -271,3 +271,11 @@ export default class AnimatedProps extends AnimatedNode {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Supported versions of JSC do not implement the newer Object.hasOwn. Remove
|
||||
// this shim when they do.
|
||||
// $FlowIgnore[method-unbinding]
|
||||
const _hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
const hasOwn: (obj: $ReadOnly<{...}>, prop: string) => boolean =
|
||||
// $FlowIgnore[method-unbinding]
|
||||
Object.hasOwn ?? ((obj, prop) => _hasOwnProp.call(obj, prop));
|
||||
|
||||
@@ -35,7 +35,7 @@ function createAnimatedStyle(
|
||||
const key = keys[ii];
|
||||
const value = inputStyle[key];
|
||||
|
||||
if (allowlist == null || Object.hasOwn(allowlist, key)) {
|
||||
if (allowlist == null || hasOwn(allowlist, key)) {
|
||||
let node;
|
||||
if (value != null && key === 'transform') {
|
||||
node = ReactNativeFeatureFlags.shouldUseAnimatedObjectForTransform()
|
||||
@@ -241,3 +241,11 @@ export default class AnimatedStyle extends AnimatedWithChildren {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Supported versions of JSC do not implement the newer Object.hasOwn. Remove
|
||||
// this shim when they do.
|
||||
// $FlowIgnore[method-unbinding]
|
||||
const _hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
const hasOwn: (obj: $ReadOnly<{...}>, prop: string) => boolean =
|
||||
// $FlowIgnore[method-unbinding]
|
||||
Object.hasOwn ?? ((obj, prop) => _hasOwnProp.call(obj, prop));
|
||||
|
||||
+11
-3
@@ -28,6 +28,15 @@ type FormDataPart =
|
||||
...
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a FormData filename compliant with RFC 2183
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
|
||||
*/
|
||||
function encodeFilename(filename: string): string {
|
||||
return encodeURIComponent(filename.replace(/\//g, '_'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Polyfill for XMLHttpRequest2 FormData API, allowing multipart POST requests
|
||||
* with mixed data (string, native files) to be submitted via XMLHttpRequest.
|
||||
@@ -82,9 +91,8 @@ class FormData {
|
||||
// content type (cf. web Blob interface.)
|
||||
if (typeof value === 'object' && !Array.isArray(value) && value) {
|
||||
if (typeof value.name === 'string') {
|
||||
headers['content-disposition'] += `; filename="${
|
||||
value.name
|
||||
}"; filename*=utf-8''${encodeURI(value.name)}`;
|
||||
headers['content-disposition'] +=
|
||||
`; filename="${encodeFilename(value.name)}"`;
|
||||
}
|
||||
if (typeof value.type === 'string') {
|
||||
headers['content-type'] = value.type;
|
||||
|
||||
@@ -48,8 +48,7 @@ describe('FormData', function () {
|
||||
type: 'image/jpeg',
|
||||
name: 'photo.jpg',
|
||||
headers: {
|
||||
'content-disposition':
|
||||
'form-data; name="photo"; filename="photo.jpg"; filename*=utf-8\'\'photo.jpg',
|
||||
'content-disposition': 'form-data; name="photo"; filename="photo.jpg"',
|
||||
'content-type': 'image/jpeg',
|
||||
},
|
||||
fieldName: 'photo',
|
||||
@@ -70,7 +69,7 @@ describe('FormData', function () {
|
||||
name: '测试photo.jpg',
|
||||
headers: {
|
||||
'content-disposition':
|
||||
'form-data; name="photo"; filename="测试photo.jpg"; filename*=utf-8\'\'%E6%B5%8B%E8%AF%95photo.jpg',
|
||||
'form-data; name="photo"; filename="%E6%B5%8B%E8%AF%95photo.jpg"',
|
||||
'content-type': 'image/jpeg',
|
||||
},
|
||||
fieldName: 'photo',
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import setUpReactFabricPublicInstanceFantomTests from './setUpReactFabricPublicInstanceFantomTests';
|
||||
|
||||
setUpReactFabricPublicInstanceFantomTests({isModern: false});
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import './setUpFeatureFlags';
|
||||
import setUpReactFabricPublicInstanceFantomTests from './setUpReactFabricPublicInstanceFantomTests';
|
||||
|
||||
setUpReactFabricPublicInstanceFantomTests({isModern: true});
|
||||
packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/setUpFeatureFlags.js
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import * as ReactNativeFeatureFlags from '../../../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
|
||||
ReactNativeFeatureFlags.override({
|
||||
enableAccessToHostTreeInFabric: () => true,
|
||||
});
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import '../../../Core/InitializeCore.js';
|
||||
|
||||
import * as ReactNativeTester from '../../../../src/private/__tests__/ReactNativeTester';
|
||||
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
import TextInputState from '../../../Components/TextInput/TextInputState';
|
||||
import View from '../../../Components/View/View';
|
||||
import ReactFabricHostComponent from '../ReactFabricHostComponent';
|
||||
import nullthrows from 'nullthrows';
|
||||
import * as React from 'react';
|
||||
|
||||
export default function setUpTests({isModern}: {isModern: boolean}) {
|
||||
// TODO: move these tests to the test file for `ReactNativeElement` when the legacy implementation is removed.
|
||||
describe(`ReactFabricPublicInstance (${isModern ? 'modern' : 'legacy'})`, () => {
|
||||
it('should provide instances of the right class as refs in host components', () => {
|
||||
let node;
|
||||
|
||||
const root = ReactNativeTester.createRoot();
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
ref={receivedNode => {
|
||||
node = receivedNode;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
expect(node).toBeInstanceOf(
|
||||
isModern ? ReactNativeElement : ReactFabricHostComponent,
|
||||
);
|
||||
});
|
||||
|
||||
describe('blur', () => {
|
||||
test('blur() invokes TextInputState', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
const blurTextInput = jest.fn();
|
||||
|
||||
// We don't support view commands in Fantom yet, so we have to mock this.
|
||||
TextInputState.blurTextInput = blurTextInput;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
node.blur();
|
||||
});
|
||||
|
||||
expect(blurTextInput).toHaveBeenCalledTimes(1);
|
||||
expect(blurTextInput.mock.calls).toEqual([[node]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('focus', () => {
|
||||
test('focus() invokes TextInputState', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
const focusTextInput = jest.fn();
|
||||
|
||||
// We don't support view commands in Fantom yet, so we have to mock this.
|
||||
TextInputState.focusTextInput = focusTextInput;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
node.focus();
|
||||
});
|
||||
|
||||
expect(focusTextInput).toHaveBeenCalledTimes(1);
|
||||
expect(focusTextInput.mock.calls).toEqual([[node]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('measure', () => {
|
||||
it('component.measure(...) invokes callback', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measure(callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 10, 10]]);
|
||||
});
|
||||
|
||||
it('unmounted.measure(...) does nothing', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measure(callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('measureInWindow', () => {
|
||||
it('component.measureInWindow(...) invokes callback', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measureInWindow(callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
|
||||
});
|
||||
|
||||
it('unmounted.measureInWindow(...) does nothing', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeNode = node;
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(maybeNode);
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measureInWindow(callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('measureLayout', () => {
|
||||
it('component.measureLayout(component, ...) invokes callback', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeParentNode;
|
||||
let maybeChildNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeParentNode = node;
|
||||
}}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={node => {
|
||||
maybeChildNode = node;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(maybeParentNode);
|
||||
const childNode = nullthrows(maybeChildNode);
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[20, 20, 10, 10]]);
|
||||
});
|
||||
|
||||
it('unmounted.measureLayout(component, ...) does nothing', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeParentNode;
|
||||
let maybeChildNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeParentNode = node;
|
||||
}}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={node => {
|
||||
maybeChildNode = node;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(maybeParentNode);
|
||||
const childNode = nullthrows(maybeChildNode);
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
|
||||
);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('component.measureLayout(unmounted, ...) does nothing', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeParentNode;
|
||||
let maybeChildNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeParentNode = node;
|
||||
}}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={node => {
|
||||
maybeChildNode = node;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(maybeParentNode);
|
||||
const childNode = nullthrows(maybeChildNode);
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
|
||||
);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
parentNode.measureLayout(childNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('unmounted.measureLayout(unmounted, ...) does nothing', () => {
|
||||
const root = ReactNativeTester.createRoot();
|
||||
|
||||
let maybeParentNode;
|
||||
let maybeChildNode;
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={node => {
|
||||
maybeParentNode = node;
|
||||
}}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={node => {
|
||||
maybeChildNode = node;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(maybeParentNode);
|
||||
const childNode = nullthrows(maybeChildNode);
|
||||
|
||||
ReactNativeTester.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -468,8 +468,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)init);
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
if (_bridge.valid) {
|
||||
id instance = self.instance;
|
||||
RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@)", self, instance);
|
||||
RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@)", self, self.instance);
|
||||
}
|
||||
return _methodQueue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
/**
|
||||
* UIView class for root <ModalHostView> component.
|
||||
*/
|
||||
@interface RCTModalHostViewComponentView : RCTViewComponentView
|
||||
@interface RCTModalHostViewComponentView : RCTViewComponentView <UIAdaptivePresentationControllerDelegate>
|
||||
|
||||
/**
|
||||
* Subclasses may override this method and present the modal on different view controller.
|
||||
|
||||
+12
@@ -149,6 +149,8 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
||||
{
|
||||
BOOL shouldBePresented = !_isPresented && _shouldPresent && self.window;
|
||||
if (shouldBePresented) {
|
||||
self.viewController.presentationController.delegate = self;
|
||||
|
||||
_isPresented = YES;
|
||||
[self presentViewController:self.viewController
|
||||
animated:_shouldAnimatePresentation
|
||||
@@ -274,6 +276,16 @@ static ModalHostViewEventEmitter::OnOrientationChange onOrientationChangeStruct(
|
||||
[childComponentView removeFromSuperview];
|
||||
}
|
||||
|
||||
#pragma mark - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
- (void)presentationControllerDidAttemptToDismiss:(UIPresentationController *)controller
|
||||
{
|
||||
auto eventEmitter = [self modalEventEmitter];
|
||||
if (eventEmitter) {
|
||||
eventEmitter->onRequestClose({});
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -121,8 +121,8 @@ using namespace facebook::react;
|
||||
auto &props = *sharedProps;
|
||||
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -136,8 +136,8 @@ using namespace facebook::react;
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(0));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -216,8 +216,8 @@ using namespace facebook::react;
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(30));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(50));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -260,8 +260,8 @@ using namespace facebook::react;
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(90));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(50));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -418,8 +418,8 @@ static ParagraphShadowNode::ConcreteState::Shared stateWithShadowNode(
|
||||
auto &props = *sharedProps;
|
||||
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -434,8 +434,8 @@ static ParagraphShadowNode::ConcreteState::Shared stateWithShadowNode(
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(90));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(20));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(20));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
|
||||
@@ -87,6 +87,9 @@ CGFloat RCTCoreGraphicsFloatFromYogaValue(YGValue value, CGFloat baseFloatValue)
|
||||
return RCTCoreGraphicsFloatFromYogaFloat(value.value) * baseFloatValue;
|
||||
case YGUnitAuto:
|
||||
case YGUnitUndefined:
|
||||
case YGUnitMaxContent:
|
||||
case YGUnitFitContent:
|
||||
case YGUnitStretch:
|
||||
return baseFloatValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ typedef NS_ENUM(unsigned int, meta_prop_t) {
|
||||
#define RCT_SET_YGVALUE(ygvalue, setter, ...) \
|
||||
switch (ygvalue.unit) { \
|
||||
case YGUnitAuto: \
|
||||
case YGUnitMaxContent: \
|
||||
case YGUnitFitContent: \
|
||||
case YGUnitStretch: \
|
||||
case YGUnitUndefined: \
|
||||
setter(__VA_ARGS__, YGUndefined); \
|
||||
break; \
|
||||
@@ -88,6 +91,35 @@ typedef NS_ENUM(unsigned int, meta_prop_t) {
|
||||
case YGUnitPercent: \
|
||||
setter##Percent(__VA_ARGS__, ygvalue.value); \
|
||||
break; \
|
||||
case YGUnitMaxContent: \
|
||||
case YGUnitFitContent: \
|
||||
case YGUnitStretch: \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define RCT_SET_YGVALUE_AUTO_INTRINSIC(ygvalue, setter, ...) \
|
||||
switch (ygvalue.unit) { \
|
||||
case YGUnitAuto: \
|
||||
setter##Auto(__VA_ARGS__); \
|
||||
break; \
|
||||
case YGUnitMaxContent: \
|
||||
setter##MaxContent(__VA_ARGS__); \
|
||||
break; \
|
||||
case YGUnitFitContent: \
|
||||
setter##FitContent(__VA_ARGS__); \
|
||||
break; \
|
||||
case YGUnitStretch: \
|
||||
setter##Stretch(__VA_ARGS__); \
|
||||
break; \
|
||||
case YGUnitUndefined: \
|
||||
setter(__VA_ARGS__, YGUndefined); \
|
||||
break; \
|
||||
case YGUnitPoint: \
|
||||
setter(__VA_ARGS__, ygvalue.value); \
|
||||
break; \
|
||||
case YGUnitPercent: \
|
||||
setter##Percent(__VA_ARGS__, ygvalue.value); \
|
||||
break; \
|
||||
}
|
||||
|
||||
static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node)
|
||||
@@ -483,14 +515,14 @@ RCT_BORDER_PROPERTY(Start, START)
|
||||
RCT_BORDER_PROPERTY(End, END)
|
||||
|
||||
// Dimensions
|
||||
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
|
||||
-(void)set##setProp : (YGValue)value \
|
||||
{ \
|
||||
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \
|
||||
} \
|
||||
-(YGValue)getProp \
|
||||
{ \
|
||||
return YGNodeStyleGet##cssProp(_yogaNode); \
|
||||
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
|
||||
-(void)set##setProp : (YGValue)value \
|
||||
{ \
|
||||
RCT_SET_YGVALUE_AUTO_INTRINSIC(value, YGNodeStyleSet##cssProp, _yogaNode); \
|
||||
} \
|
||||
-(YGValue)getProp \
|
||||
{ \
|
||||
return YGNodeStyleGet##cssProp(_yogaNode); \
|
||||
}
|
||||
|
||||
#define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
|
||||
@@ -634,7 +666,7 @@ RCTShadowViewMeasure(YGNodeConstRef node, float width, YGMeasureMode widthMode,
|
||||
|
||||
- (void)setFlexBasis:(YGValue)value
|
||||
{
|
||||
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode);
|
||||
RCT_SET_YGVALUE_AUTO_INTRINSIC(value, YGNodeStyleSetFlexBasis, _yogaNode);
|
||||
}
|
||||
|
||||
- (YGValue)flexBasis
|
||||
|
||||
@@ -426,6 +426,10 @@ public abstract interface class com/facebook/react/ReactRootView$ReactRootViewEv
|
||||
public abstract fun onAttachedToReactInstance (Lcom/facebook/react/ReactRootView;)V
|
||||
}
|
||||
|
||||
public abstract class com/facebook/react/TurboReactPackage : com/facebook/react/BaseReactPackage {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/ViewManagerOnDemandReactPackage {
|
||||
public abstract fun createViewManager (Lcom/facebook/react/bridge/ReactApplicationContext;Ljava/lang/String;)Lcom/facebook/react/uimanager/ViewManager;
|
||||
public abstract fun getViewManagerNames (Lcom/facebook/react/bridge/ReactApplicationContext;)Ljava/util/Collection;
|
||||
@@ -776,16 +780,6 @@ public abstract class com/facebook/react/bridge/GuardedAsyncTask : android/os/As
|
||||
protected abstract fun doInBackgroundGuarded ([Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract class com/facebook/react/bridge/GuardedResultAsyncTask : android/os/AsyncTask {
|
||||
protected fun <init> (Lcom/facebook/react/bridge/JSExceptionHandler;)V
|
||||
protected fun <init> (Lcom/facebook/react/bridge/ReactContext;)V
|
||||
protected synthetic fun doInBackground ([Ljava/lang/Object;)Ljava/lang/Object;
|
||||
protected final fun doInBackground ([Ljava/lang/Void;)Ljava/lang/Object;
|
||||
protected abstract fun doInBackgroundGuarded ()Ljava/lang/Object;
|
||||
protected final fun onPostExecute (Ljava/lang/Object;)V
|
||||
protected abstract fun onPostExecuteGuarded (Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract class com/facebook/react/bridge/GuardedRunnable : java/lang/Runnable {
|
||||
public fun <init> (Lcom/facebook/react/bridge/JSExceptionHandler;)V
|
||||
public fun <init> (Lcom/facebook/react/bridge/ReactContext;)V
|
||||
@@ -4091,10 +4085,6 @@ public abstract class com/facebook/react/uimanager/BaseViewManagerDelegate : com
|
||||
public fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/uimanager/ComponentNameResolver {
|
||||
public abstract fun getComponentNames ()[Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/uimanager/DisplayMetricsHolder {
|
||||
public static final field INSTANCE Lcom/facebook/react/uimanager/DisplayMetricsHolder;
|
||||
public static final fun getDisplayMetricsWritableMap (D)Lcom/facebook/react/bridge/WritableMap;
|
||||
@@ -4106,22 +4096,6 @@ public final class com/facebook/react/uimanager/DisplayMetricsHolder {
|
||||
public static final fun setWindowDisplayMetrics (Landroid/util/DisplayMetrics;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/uimanager/FabricViewStateManager {
|
||||
public fun <init> ()V
|
||||
public fun getStateData ()Lcom/facebook/react/bridge/ReadableMap;
|
||||
public fun hasStateWrapper ()Z
|
||||
public fun setState (Lcom/facebook/react/uimanager/FabricViewStateManager$StateUpdateCallback;)V
|
||||
public fun setStateWrapper (Lcom/facebook/react/uimanager/StateWrapper;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/uimanager/FabricViewStateManager$HasFabricViewStateManager {
|
||||
public abstract fun getFabricViewStateManager ()Lcom/facebook/react/uimanager/FabricViewStateManager;
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/uimanager/FabricViewStateManager$StateUpdateCallback {
|
||||
public abstract fun getStateUpdate ()Lcom/facebook/react/bridge/WritableMap;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/uimanager/FloatUtil {
|
||||
public static final field INSTANCE Lcom/facebook/react/uimanager/FloatUtil;
|
||||
public static final fun floatsEqual (FF)Z
|
||||
@@ -7137,45 +7111,6 @@ public final class com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout
|
||||
public fun setRefreshing (Z)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/switchview/ReactSwitchManager : com/facebook/react/uimanager/SimpleViewManager, com/facebook/react/viewmanagers/AndroidSwitchManagerInterface {
|
||||
public static final field REACT_CLASS Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
protected synthetic fun addEventEmitters (Lcom/facebook/react/uimanager/ThemedReactContext;Landroid/view/View;)V
|
||||
protected fun addEventEmitters (Lcom/facebook/react/uimanager/ThemedReactContext;Lcom/facebook/react/views/switchview/ReactSwitch;)V
|
||||
public fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/LayoutShadowNode;
|
||||
public synthetic fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/ReactShadowNode;
|
||||
protected synthetic fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View;
|
||||
protected fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Lcom/facebook/react/views/switchview/ReactSwitch;
|
||||
protected fun getDelegate ()Lcom/facebook/react/uimanager/ViewManagerDelegate;
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getShadowNodeClass ()Ljava/lang/Class;
|
||||
public fun measure (Landroid/content/Context;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;FLcom/facebook/yoga/YogaMeasureMode;FLcom/facebook/yoga/YogaMeasureMode;[F)J
|
||||
public synthetic fun receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
|
||||
public fun receiveCommand (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
|
||||
public synthetic fun setBackgroundColor (Landroid/view/View;I)V
|
||||
public fun setBackgroundColor (Lcom/facebook/react/views/switchview/ReactSwitch;I)V
|
||||
public synthetic fun setDisabled (Landroid/view/View;Z)V
|
||||
public fun setDisabled (Lcom/facebook/react/views/switchview/ReactSwitch;Z)V
|
||||
public synthetic fun setEnabled (Landroid/view/View;Z)V
|
||||
public fun setEnabled (Lcom/facebook/react/views/switchview/ReactSwitch;Z)V
|
||||
public synthetic fun setNativeValue (Landroid/view/View;Z)V
|
||||
public fun setNativeValue (Lcom/facebook/react/views/switchview/ReactSwitch;Z)V
|
||||
public synthetic fun setOn (Landroid/view/View;Z)V
|
||||
public fun setOn (Lcom/facebook/react/views/switchview/ReactSwitch;Z)V
|
||||
public synthetic fun setThumbColor (Landroid/view/View;Ljava/lang/Integer;)V
|
||||
public fun setThumbColor (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/Integer;)V
|
||||
public synthetic fun setThumbTintColor (Landroid/view/View;Ljava/lang/Integer;)V
|
||||
public fun setThumbTintColor (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/Integer;)V
|
||||
public synthetic fun setTrackColorForFalse (Landroid/view/View;Ljava/lang/Integer;)V
|
||||
public fun setTrackColorForFalse (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/Integer;)V
|
||||
public synthetic fun setTrackColorForTrue (Landroid/view/View;Ljava/lang/Integer;)V
|
||||
public fun setTrackColorForTrue (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/Integer;)V
|
||||
public synthetic fun setTrackTintColor (Landroid/view/View;Ljava/lang/Integer;)V
|
||||
public fun setTrackTintColor (Lcom/facebook/react/views/switchview/ReactSwitch;Ljava/lang/Integer;)V
|
||||
public synthetic fun setValue (Landroid/view/View;Z)V
|
||||
public fun setValue (Lcom/facebook/react/views/switchview/ReactSwitch;Z)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/text/DefaultStyleValuesUtil {
|
||||
public static final field INSTANCE Lcom/facebook/react/views/text/DefaultStyleValuesUtil;
|
||||
public static final fun getDefaultTextColor (Landroid/content/Context;)Landroid/content/res/ColorStateList;
|
||||
|
||||
@@ -591,7 +591,8 @@ android {
|
||||
"src/main/res/shell",
|
||||
"src/main/res/views/alert",
|
||||
"src/main/res/views/modal",
|
||||
"src/main/res/views/uimanager"))
|
||||
"src/main/res/views/uimanager",
|
||||
"src/main/res/views/view"))
|
||||
java.exclude("com/facebook/react/processing")
|
||||
java.exclude("com/facebook/react/module/processing")
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react
|
||||
|
||||
@Deprecated(
|
||||
message = "Use BaseReactPackage instead",
|
||||
replaceWith = ReplaceWith(expression = "BaseReactPackage"))
|
||||
public abstract class TurboReactPackage : BaseReactPackage() {}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
/**
|
||||
* Abstract base for a AsyncTask with result support that should have any RuntimeExceptions it
|
||||
* throws handled by the {@link JSExceptionHandler} registered if the app is in dev mode.
|
||||
*/
|
||||
public abstract class GuardedResultAsyncTask<Result> extends AsyncTask<Void, Void, Result> {
|
||||
|
||||
private final JSExceptionHandler mExceptionHandler;
|
||||
|
||||
protected GuardedResultAsyncTask(ReactContext reactContext) {
|
||||
this(reactContext.getExceptionHandler());
|
||||
}
|
||||
|
||||
protected GuardedResultAsyncTask(JSExceptionHandler exceptionHandler) {
|
||||
mExceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Result doInBackground(Void... params) {
|
||||
try {
|
||||
return doInBackgroundGuarded();
|
||||
} catch (RuntimeException e) {
|
||||
mExceptionHandler.handleException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void onPostExecute(Result result) {
|
||||
try {
|
||||
onPostExecuteGuarded(result);
|
||||
} catch (RuntimeException e) {
|
||||
mExceptionHandler.handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Result doInBackgroundGuarded();
|
||||
|
||||
protected abstract void onPostExecuteGuarded(Result result);
|
||||
}
|
||||
+8
-2
@@ -445,12 +445,18 @@ public class FabricUIManager
|
||||
|
||||
@Override
|
||||
public void markActiveTouchForTag(int surfaceId, int reactTag) {
|
||||
mMountingManager.getSurfaceManager(surfaceId).markActiveTouchForTag(reactTag);
|
||||
SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
|
||||
if (surfaceMountingManager != null) {
|
||||
surfaceMountingManager.markActiveTouchForTag(reactTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sweepActiveTouchForTag(int surfaceId, int reactTag) {
|
||||
mMountingManager.getSurfaceManager(surfaceId).sweepActiveTouchForTag(reactTag);
|
||||
SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
|
||||
if (surfaceMountingManager != null) {
|
||||
surfaceMountingManager.sweepActiveTouchForTag(reactTag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+8
-5
@@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.facebook.fbreact.specs.NativeAppearanceSpec
|
||||
import com.facebook.react.bridge.Arguments
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.react.module.annotations.ReactModule
|
||||
|
||||
/** Module that exposes the user's preferred color scheme. */
|
||||
@@ -58,11 +59,13 @@ constructor(
|
||||
}
|
||||
|
||||
public override fun setColorScheme(style: String) {
|
||||
when (style) {
|
||||
"dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
"light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
"unspecified" ->
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
UiThreadUtil.runOnUiThread {
|
||||
when (style) {
|
||||
"dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
"light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
"unspecified" ->
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -84,6 +84,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
view.setTag(R.id.accessibility_actions, null);
|
||||
view.setTag(R.id.accessibility_value, null);
|
||||
view.setTag(R.id.accessibility_state_expanded, null);
|
||||
view.setTag(R.id.view_clipped, null);
|
||||
|
||||
// This indirectly calls (and resets):
|
||||
// setTranslationX
|
||||
|
||||
+4
-5
@@ -5,13 +5,12 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
package com.facebook.react.uimanager
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStripAny;
|
||||
import com.facebook.proguard.annotations.DoNotStripAny
|
||||
|
||||
@DoNotStripAny
|
||||
public interface ComponentNameResolver {
|
||||
|
||||
internal interface ComponentNameResolver {
|
||||
/* returns a list of all the component names that are registered in React Native. */
|
||||
String[] getComponentNames();
|
||||
public val componentNames: Array<String>?
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
/**
|
||||
* This is a helper base class for ViewGroups that use Fabric State.
|
||||
*
|
||||
* <p>Reason to use this: UpdateState calls from the View layer to the Fabric core can fail, and
|
||||
* optionally Fabric will call a "failure callback" if that happens. This class abstracts that and
|
||||
* makes it easier ensure that State in Fabric is always up-to-date.
|
||||
*
|
||||
* <p>1. Whenever ViewManager.updateState is called, call View.setStateWrapper. 2. Instead of
|
||||
* calling StateWrapper.updateState directly, call View.setState and it will automatically keep
|
||||
* retrying the UpdateState call until it succeeds; or you call setState again; or the View layer is
|
||||
* updated with a newer StateWrapper.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
@Deprecated(
|
||||
since =
|
||||
"Deprecated class since v0.73.0, please use com.facebook.react.uimanager.StateWrapper"
|
||||
+ " instead.",
|
||||
forRemoval = true)
|
||||
public class FabricViewStateManager {
|
||||
private static final String TAG = "FabricViewStateManager";
|
||||
|
||||
@Deprecated
|
||||
public interface HasFabricViewStateManager {
|
||||
FabricViewStateManager getFabricViewStateManager();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public interface StateUpdateCallback {
|
||||
WritableMap getStateUpdate();
|
||||
}
|
||||
|
||||
@Nullable private StateWrapper mStateWrapper = null;
|
||||
|
||||
@Deprecated
|
||||
public void setStateWrapper(StateWrapper stateWrapper) {
|
||||
mStateWrapper = stateWrapper;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean hasStateWrapper() {
|
||||
return mStateWrapper != null;
|
||||
}
|
||||
|
||||
private void setState(
|
||||
@Nullable final StateWrapper stateWrapper,
|
||||
final StateUpdateCallback stateUpdateCallback,
|
||||
final int numTries) {
|
||||
// The StateWrapper will change, breaking the async loop, whenever the UpdateState MountItem
|
||||
// is executed.
|
||||
// The caller is responsible for detecting if data is up-to-date, and doing nothing, or
|
||||
// detecting if state is stale and calling setState again.
|
||||
if (stateWrapper == null) {
|
||||
FLog.e(TAG, "setState called without a StateWrapper");
|
||||
return;
|
||||
}
|
||||
if (stateWrapper != mStateWrapper) {
|
||||
return;
|
||||
}
|
||||
// We bail out after an arbitrary number of tries. In practice this should never go higher
|
||||
// than 2 or 3, but there's nothing guaranteeing that.
|
||||
if (numTries > 60) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Nullable WritableMap stateUpdate = stateUpdateCallback.getStateUpdate();
|
||||
if (stateUpdate == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: State update cannot fail; remove `failureRunnable` and custom retrying logic.
|
||||
stateWrapper.updateState(stateUpdate);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setState(final StateUpdateCallback stateUpdateCallback) {
|
||||
setState(mStateWrapper, stateUpdateCallback, 0);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public @Nullable ReadableMap getStateData() {
|
||||
return mStateWrapper != null ? mStateWrapper.getStateData() : null;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -5,10 +5,10 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager.events;
|
||||
package com.facebook.react.uimanager.events
|
||||
|
||||
public interface BatchEventDispatchedListener {
|
||||
public fun interface BatchEventDispatchedListener {
|
||||
|
||||
/** Called after a batch of low priority events has been dispatched. */
|
||||
void onBatchEventDispatched();
|
||||
public fun onBatchEventDispatched()
|
||||
}
|
||||
-232
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// switchview because switch is a keyword
|
||||
package com.facebook.react.views.switchview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.SimpleViewManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.ViewManagerDelegate;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.viewmanagers.AndroidSwitchManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.AndroidSwitchManagerInterface;
|
||||
import com.facebook.yoga.YogaMeasureFunction;
|
||||
import com.facebook.yoga.YogaMeasureMode;
|
||||
import com.facebook.yoga.YogaMeasureOutput;
|
||||
import com.facebook.yoga.YogaNode;
|
||||
|
||||
/** View manager for {@link ReactSwitch} components. */
|
||||
public class ReactSwitchManager extends SimpleViewManager<ReactSwitch>
|
||||
implements AndroidSwitchManagerInterface<ReactSwitch> {
|
||||
|
||||
public static final String REACT_CLASS = "AndroidSwitch";
|
||||
|
||||
static class ReactSwitchShadowNode extends LayoutShadowNode implements YogaMeasureFunction {
|
||||
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private boolean mMeasured;
|
||||
|
||||
private ReactSwitchShadowNode() {
|
||||
initMeasureFunction();
|
||||
}
|
||||
|
||||
private void initMeasureFunction() {
|
||||
setMeasureFunction(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long measure(
|
||||
YogaNode node,
|
||||
float width,
|
||||
YogaMeasureMode widthMode,
|
||||
float height,
|
||||
YogaMeasureMode heightMode) {
|
||||
if (!mMeasured) {
|
||||
// Create a switch with the default config and measure it; since we don't (currently)
|
||||
// support setting custom switch text, this is fine, as all switches will measure the same
|
||||
// on a specific device/theme/locale combination.
|
||||
ReactSwitch reactSwitch = new ReactSwitch(getThemedContext());
|
||||
reactSwitch.setShowText(false);
|
||||
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
reactSwitch.measure(spec, spec);
|
||||
mWidth = reactSwitch.getMeasuredWidth();
|
||||
mHeight = reactSwitch.getMeasuredHeight();
|
||||
mMeasured = true;
|
||||
}
|
||||
|
||||
return YogaMeasureOutput.make(mWidth, mHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private static final CompoundButton.OnCheckedChangeListener ON_CHECKED_CHANGE_LISTENER =
|
||||
new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
ReactContext reactContext = (ReactContext) buttonView.getContext();
|
||||
|
||||
int reactTag = buttonView.getId();
|
||||
UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag)
|
||||
.dispatchEvent(
|
||||
new ReactSwitchEvent(
|
||||
UIManagerHelper.getSurfaceId(reactContext), reactTag, isChecked));
|
||||
}
|
||||
};
|
||||
|
||||
private final ViewManagerDelegate<ReactSwitch> mDelegate;
|
||||
|
||||
public ReactSwitchManager() {
|
||||
mDelegate = new AndroidSwitchManagerDelegate<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutShadowNode createShadowNodeInstance() {
|
||||
return new ReactSwitchShadowNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getShadowNodeClass() {
|
||||
return ReactSwitchShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactSwitch createViewInstance(ThemedReactContext context) {
|
||||
ReactSwitch view = new ReactSwitch(context);
|
||||
view.setShowText(false);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(ReactSwitch view, @ColorInt int backgroundColor) {
|
||||
view.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "disabled", defaultBoolean = false)
|
||||
public void setDisabled(ReactSwitch view, boolean disabled) {
|
||||
view.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = ViewProps.ENABLED, defaultBoolean = true)
|
||||
public void setEnabled(ReactSwitch view, boolean enabled) {
|
||||
view.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = ViewProps.ON)
|
||||
public void setOn(ReactSwitch view, boolean on) {
|
||||
setValueInternal(view, on);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "value")
|
||||
public void setValue(ReactSwitch view, boolean value) {
|
||||
setValueInternal(view, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "thumbTintColor", customType = "Color")
|
||||
public void setThumbTintColor(ReactSwitch view, @Nullable Integer color) {
|
||||
this.setThumbColor(view, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "thumbColor", customType = "Color")
|
||||
public void setThumbColor(ReactSwitch view, @Nullable Integer color) {
|
||||
view.setThumbColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "trackColorForFalse", customType = "Color")
|
||||
public void setTrackColorForFalse(ReactSwitch view, @Nullable Integer color) {
|
||||
view.setTrackColorForFalse(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "trackColorForTrue", customType = "Color")
|
||||
public void setTrackColorForTrue(ReactSwitch view, @Nullable Integer color) {
|
||||
view.setTrackColorForTrue(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ReactProp(name = "trackTintColor", customType = "Color")
|
||||
public void setTrackTintColor(ReactSwitch view, @Nullable Integer color) {
|
||||
view.setTrackColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNativeValue(ReactSwitch view, boolean value) {
|
||||
setValueInternal(view, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveCommand(
|
||||
@NonNull ReactSwitch view, String commandId, @Nullable ReadableArray args) {
|
||||
switch (commandId) {
|
||||
case "setNativeValue":
|
||||
setValueInternal(view, args != null && args.getBoolean(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEventEmitters(final ThemedReactContext reactContext, final ReactSwitch view) {
|
||||
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewManagerDelegate<ReactSwitch> getDelegate() {
|
||||
return mDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long measure(
|
||||
Context context,
|
||||
ReadableMap localData,
|
||||
ReadableMap props,
|
||||
ReadableMap state,
|
||||
float width,
|
||||
YogaMeasureMode widthMode,
|
||||
float height,
|
||||
YogaMeasureMode heightMode,
|
||||
@Nullable float[] attachmentsPositions) {
|
||||
ReactSwitch view = new ReactSwitch(context);
|
||||
view.setShowText(false);
|
||||
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
view.measure(measureSpec, measureSpec);
|
||||
return YogaMeasureOutput.make(
|
||||
PixelUtil.toDIPFromPixel(view.getMeasuredWidth()),
|
||||
PixelUtil.toDIPFromPixel(view.getMeasuredHeight()));
|
||||
}
|
||||
|
||||
private static void setValueInternal(ReactSwitch view, boolean value) {
|
||||
// we set the checked change listener to null and then restore it so that we don't fire an
|
||||
// onChange event to JS when JS itself is updating the value of the switch
|
||||
view.setOnCheckedChangeListener(null);
|
||||
view.setOn(value);
|
||||
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER);
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.switchview
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import androidx.annotation.ColorInt
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.uimanager.BaseViewManager
|
||||
import com.facebook.react.uimanager.PixelUtil
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.UIManagerHelper
|
||||
import com.facebook.react.uimanager.ViewManagerDelegate
|
||||
import com.facebook.react.uimanager.ViewProps
|
||||
import com.facebook.react.uimanager.annotations.ReactProp
|
||||
import com.facebook.react.viewmanagers.AndroidSwitchManagerDelegate
|
||||
import com.facebook.react.viewmanagers.AndroidSwitchManagerInterface
|
||||
import com.facebook.yoga.YogaMeasureMode
|
||||
import com.facebook.yoga.YogaMeasureOutput
|
||||
|
||||
internal class ReactSwitchManager :
|
||||
BaseViewManager<ReactSwitch, ReactSwitchShadowNode>(),
|
||||
AndroidSwitchManagerInterface<ReactSwitch> {
|
||||
|
||||
private val delegate: ViewManagerDelegate<ReactSwitch> = AndroidSwitchManagerDelegate(this)
|
||||
|
||||
override fun getName(): String = REACT_CLASS
|
||||
|
||||
override fun createShadowNodeInstance(): ReactSwitchShadowNode = ReactSwitchShadowNode()
|
||||
|
||||
override fun getShadowNodeClass(): Class<ReactSwitchShadowNode> =
|
||||
ReactSwitchShadowNode::class.java
|
||||
|
||||
override fun createViewInstance(context: ThemedReactContext): ReactSwitch =
|
||||
ReactSwitch(context).apply { showText = false }
|
||||
|
||||
override fun setBackgroundColor(view: ReactSwitch, @ColorInt backgroundColor: Int) {
|
||||
view.setBackgroundColor(backgroundColor)
|
||||
}
|
||||
|
||||
@ReactProp(name = "disabled", defaultBoolean = false)
|
||||
override fun setDisabled(view: ReactSwitch, disabled: Boolean) {
|
||||
view.isEnabled = !disabled
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.ENABLED, defaultBoolean = true)
|
||||
override fun setEnabled(view: ReactSwitch, enabled: Boolean) {
|
||||
view.isEnabled = enabled
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.ON)
|
||||
override fun setOn(view: ReactSwitch, on: Boolean) {
|
||||
setValueInternal(view, on)
|
||||
}
|
||||
|
||||
@ReactProp(name = "value")
|
||||
override fun setValue(view: ReactSwitch, value: Boolean) {
|
||||
setValueInternal(view, value)
|
||||
}
|
||||
|
||||
@ReactProp(name = "thumbTintColor", customType = "Color")
|
||||
override fun setThumbTintColor(view: ReactSwitch, color: Int?) {
|
||||
setThumbColor(view, color)
|
||||
}
|
||||
|
||||
@ReactProp(name = "thumbColor", customType = "Color")
|
||||
override fun setThumbColor(view: ReactSwitch, color: Int?) {
|
||||
view.setThumbColor(color)
|
||||
}
|
||||
|
||||
@ReactProp(name = "trackColorForFalse", customType = "Color")
|
||||
override fun setTrackColorForFalse(view: ReactSwitch, color: Int?) {
|
||||
view.setTrackColorForFalse(color)
|
||||
}
|
||||
|
||||
@ReactProp(name = "trackColorForTrue", customType = "Color")
|
||||
override fun setTrackColorForTrue(view: ReactSwitch, color: Int?) {
|
||||
view.setTrackColorForTrue(color)
|
||||
}
|
||||
|
||||
@ReactProp(name = "trackTintColor", customType = "Color")
|
||||
override fun setTrackTintColor(view: ReactSwitch, color: Int?) {
|
||||
view.setTrackColor(color)
|
||||
}
|
||||
|
||||
override fun setNativeValue(view: ReactSwitch, value: Boolean) {
|
||||
setValueInternal(view, value)
|
||||
}
|
||||
|
||||
override fun receiveCommand(view: ReactSwitch, commandId: String, args: ReadableArray?) {
|
||||
when (commandId) {
|
||||
"setNativeValue" -> setValueInternal(view, args?.getBoolean(0) ?: false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addEventEmitters(reactContext: ThemedReactContext, view: ReactSwitch) {
|
||||
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER)
|
||||
}
|
||||
|
||||
override fun updateExtraData(root: ReactSwitch, extraData: Any) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun getDelegate(): ViewManagerDelegate<ReactSwitch> = delegate
|
||||
|
||||
override fun measure(
|
||||
context: Context,
|
||||
localData: ReadableMap?,
|
||||
props: ReadableMap?,
|
||||
state: ReadableMap?,
|
||||
width: Float,
|
||||
widthMode: YogaMeasureMode,
|
||||
height: Float,
|
||||
heightMode: YogaMeasureMode,
|
||||
attachmentsPositions: FloatArray?
|
||||
): Long {
|
||||
val view = ReactSwitch(context).apply { showText = false }
|
||||
val measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
|
||||
view.measure(measureSpec, measureSpec)
|
||||
return YogaMeasureOutput.make(
|
||||
PixelUtil.toDIPFromPixel(view.measuredWidth.toFloat()),
|
||||
PixelUtil.toDIPFromPixel(view.measuredHeight.toFloat()))
|
||||
}
|
||||
|
||||
private fun setValueInternal(view: ReactSwitch, value: Boolean) {
|
||||
// Temporarily remove the listener to avoid triggering JS events
|
||||
view.setOnCheckedChangeListener(null)
|
||||
view.setOn(value)
|
||||
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER)
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
public const val REACT_CLASS: String = "AndroidSwitch"
|
||||
|
||||
private val ON_CHECKED_CHANGE_LISTENER =
|
||||
CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
|
||||
val reactContext = buttonView.context as ReactContext
|
||||
val reactTag = buttonView.id
|
||||
UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag)
|
||||
?.dispatchEvent(
|
||||
ReactSwitchEvent(UIManagerHelper.getSurfaceId(reactContext), reactTag, isChecked))
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.switchview
|
||||
|
||||
import android.view.View
|
||||
import com.facebook.react.uimanager.LayoutShadowNode
|
||||
import com.facebook.yoga.YogaMeasureFunction
|
||||
import com.facebook.yoga.YogaMeasureMode
|
||||
import com.facebook.yoga.YogaMeasureOutput
|
||||
import com.facebook.yoga.YogaNode
|
||||
|
||||
internal class ReactSwitchShadowNode : LayoutShadowNode(), YogaMeasureFunction {
|
||||
private var width = 0
|
||||
private var height = 0
|
||||
private var measured = false
|
||||
|
||||
init {
|
||||
initMeasureFunction()
|
||||
}
|
||||
|
||||
private fun initMeasureFunction() {
|
||||
setMeasureFunction(this)
|
||||
}
|
||||
|
||||
override fun measure(
|
||||
node: YogaNode,
|
||||
width: Float,
|
||||
widthMode: YogaMeasureMode,
|
||||
height: Float,
|
||||
heightMode: YogaMeasureMode
|
||||
): Long {
|
||||
if (!measured) {
|
||||
// Create a switch with the default config and measure it; since we don't (currently)
|
||||
// support setting custom switch text, this is fine, as all switches will measure the same
|
||||
// on a specific device/theme/locale combination.
|
||||
val reactSwitch = ReactSwitch(themedContext)
|
||||
reactSwitch.showText = false
|
||||
val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
|
||||
reactSwitch.measure(spec, spec)
|
||||
this.width = reactSwitch.measuredWidth
|
||||
this.height = reactSwitch.measuredHeight
|
||||
measured = true
|
||||
}
|
||||
|
||||
return YogaMeasureOutput.make(this.width, this.height)
|
||||
}
|
||||
}
|
||||
+61
-12
@@ -125,6 +125,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
// {@link ViewGroup#getChildCount} so those methods may return views that are not attached.
|
||||
// This is risky but allows us to perform a correct cleanup in {@link NativeViewHierarchyManager}.
|
||||
private boolean mRemoveClippedSubviews;
|
||||
private volatile boolean mInSubviewClippingLoop;
|
||||
private @Nullable View[] mAllChildren;
|
||||
private int mAllChildrenCount;
|
||||
private @Nullable Rect mClippingRect;
|
||||
@@ -158,6 +159,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
setClipChildren(false);
|
||||
|
||||
mRemoveClippedSubviews = false;
|
||||
mInSubviewClippingLoop = false;
|
||||
mAllChildren = null;
|
||||
mAllChildrenCount = 0;
|
||||
mClippingRect = null;
|
||||
@@ -363,6 +365,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
View child = getChildAt(i);
|
||||
mAllChildren[i] = child;
|
||||
child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);
|
||||
setViewClipped(child, false);
|
||||
}
|
||||
updateClippingRect();
|
||||
} else {
|
||||
@@ -407,6 +410,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
|
||||
private void updateClippingToRect(Rect clippingRect) {
|
||||
Assertions.assertNotNull(mAllChildren);
|
||||
mInSubviewClippingLoop = true;
|
||||
int clippedSoFar = 0;
|
||||
for (int i = 0; i < mAllChildrenCount; i++) {
|
||||
try {
|
||||
@@ -415,7 +419,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
int realClippedSoFar = 0;
|
||||
Set<View> uniqueViews = new HashSet<>();
|
||||
for (int j = 0; j < i; j++) {
|
||||
realClippedSoFar += isViewClipped(mAllChildren[j]) ? 1 : 0;
|
||||
realClippedSoFar += isViewClipped(mAllChildren[j], null) ? 1 : 0;
|
||||
uniqueViews.add(mAllChildren[j]);
|
||||
}
|
||||
|
||||
@@ -436,10 +440,11 @@ public class ReactViewGroup extends ViewGroup
|
||||
+ uniqueViews.size(),
|
||||
e);
|
||||
}
|
||||
if (isViewClipped(mAllChildren[i])) {
|
||||
if (isViewClipped(mAllChildren[i], i)) {
|
||||
clippedSoFar++;
|
||||
}
|
||||
}
|
||||
mInSubviewClippingLoop = false;
|
||||
}
|
||||
|
||||
private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFar) {
|
||||
@@ -458,14 +463,16 @@ public class ReactViewGroup extends ViewGroup
|
||||
// it won't be size and located properly.
|
||||
Animation animation = child.getAnimation();
|
||||
boolean isAnimating = animation != null && !animation.hasEnded();
|
||||
if (!intersects && !isViewClipped(child) && !isAnimating) {
|
||||
if (!intersects && !isViewClipped(child, idx) && !isAnimating) {
|
||||
setViewClipped(child, true);
|
||||
// We can try saving on invalidate call here as the view that we remove is out of visible area
|
||||
// therefore invalidation is not necessary.
|
||||
removeViewInLayout(child);
|
||||
needUpdateClippingRecursive = true;
|
||||
} else if (intersects && isViewClipped(child)) {
|
||||
} else if (intersects && isViewClipped(child, idx)) {
|
||||
int adjustedIdx = idx - clippedSoFar;
|
||||
Assertions.assertCondition(adjustedIdx >= 0);
|
||||
setViewClipped(child, false);
|
||||
addViewInLayout(child, adjustedIdx, sDefaultLayoutParam, true);
|
||||
invalidate();
|
||||
needUpdateClippingRecursive = true;
|
||||
@@ -497,19 +504,21 @@ public class ReactViewGroup extends ViewGroup
|
||||
subview.getLeft(), subview.getTop(), subview.getRight(), subview.getBottom());
|
||||
|
||||
// If it was intersecting before, should be attached to the parent
|
||||
boolean oldIntersects = !isViewClipped(subview);
|
||||
boolean oldIntersects = !isViewClipped(subview, null);
|
||||
|
||||
if (intersects != oldIntersects) {
|
||||
mInSubviewClippingLoop = true;
|
||||
int clippedSoFar = 0;
|
||||
for (int i = 0; i < mAllChildrenCount; i++) {
|
||||
if (mAllChildren[i] == subview) {
|
||||
updateSubviewClipStatus(mClippingRect, i, clippedSoFar);
|
||||
break;
|
||||
}
|
||||
if (isViewClipped(mAllChildren[i])) {
|
||||
if (isViewClipped(mAllChildren[i], i)) {
|
||||
clippedSoFar++;
|
||||
}
|
||||
}
|
||||
mInSubviewClippingLoop = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,7 +550,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
@Override
|
||||
public void onViewAdded(View child) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
checkViewClippingTag(child, Boolean.FALSE);
|
||||
if (!customDrawOrderDisabled()) {
|
||||
getDrawingOrderHelper().handleAddView(child);
|
||||
setChildrenDrawingOrderEnabled(getDrawingOrderHelper().shouldEnableCustomDrawingOrder());
|
||||
@@ -554,7 +563,7 @@ public class ReactViewGroup extends ViewGroup
|
||||
@Override
|
||||
public void onViewRemoved(View child) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
checkViewClippingTag(child, Boolean.TRUE);
|
||||
if (!customDrawOrderDisabled()) {
|
||||
if (indexOfChild(child) == -1) {
|
||||
return;
|
||||
@@ -567,6 +576,21 @@ public class ReactViewGroup extends ViewGroup
|
||||
super.onViewRemoved(child);
|
||||
}
|
||||
|
||||
private void checkViewClippingTag(View child, Boolean expectedTag) {
|
||||
if (mInSubviewClippingLoop) {
|
||||
Object tag = child.getTag(R.id.view_clipped);
|
||||
if (!expectedTag.equals(tag)) {
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
"ReactViewGroup.onViewRemoved",
|
||||
new ReactNoCrashSoftException(
|
||||
"View clipping tag mismatch: tag=" + tag + " expected=" + expectedTag));
|
||||
}
|
||||
}
|
||||
if (mRemoveClippedSubviews) {
|
||||
child.setTag(R.id.view_clipped, expectedTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getChildDrawingOrder(int childCount, int index) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
@@ -638,19 +662,22 @@ public class ReactViewGroup extends ViewGroup
|
||||
/*package*/ void addViewWithSubviewClippingEnabled(
|
||||
final View child, int index, ViewGroup.LayoutParams params) {
|
||||
Assertions.assertCondition(mRemoveClippedSubviews);
|
||||
setViewClipped(child, true); // the view has not been added, so it is "clipped"
|
||||
addInArray(child, index);
|
||||
|
||||
// we add view as "clipped" and then run {@link #updateSubviewClipStatus} to conditionally
|
||||
// attach it
|
||||
Rect clippingRect = Assertions.assertNotNull(mClippingRect);
|
||||
View[] childArray = Assertions.assertNotNull(mAllChildren);
|
||||
mInSubviewClippingLoop = true;
|
||||
int clippedSoFar = 0;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (isViewClipped(childArray[i])) {
|
||||
if (isViewClipped(childArray[i], i)) {
|
||||
clippedSoFar++;
|
||||
}
|
||||
}
|
||||
updateSubviewClipStatus(clippingRect, index, clippedSoFar);
|
||||
mInSubviewClippingLoop = false;
|
||||
child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);
|
||||
|
||||
if (child instanceof ReactClippingProhibitedView) {
|
||||
@@ -685,10 +712,10 @@ public class ReactViewGroup extends ViewGroup
|
||||
View[] childArray = Assertions.assertNotNull(mAllChildren);
|
||||
view.removeOnLayoutChangeListener(mChildrenLayoutChangeListener);
|
||||
int index = indexOfChildInAllChildren(view);
|
||||
if (!isViewClipped(childArray[index])) {
|
||||
if (!isViewClipped(childArray[index], index)) {
|
||||
int clippedSoFar = 0;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (isViewClipped(childArray[i])) {
|
||||
if (isViewClipped(childArray[i], i)) {
|
||||
clippedSoFar++;
|
||||
}
|
||||
}
|
||||
@@ -709,9 +736,27 @@ public class ReactViewGroup extends ViewGroup
|
||||
|
||||
/**
|
||||
* @return {@code true} if the view has been removed from the ViewGroup.
|
||||
* @param index For logging - index of the view in {@code mAllChildren}, or {@code null} to skip
|
||||
* logging.
|
||||
*/
|
||||
private boolean isViewClipped(View view) {
|
||||
private boolean isViewClipped(View view, @Nullable Integer index) {
|
||||
Object tag = view.getTag(R.id.view_clipped);
|
||||
if (tag != null) {
|
||||
return (boolean) tag;
|
||||
}
|
||||
ViewParent parent = view.getParent();
|
||||
if (index != null) {
|
||||
ReactSoftExceptionLogger.logSoftException(
|
||||
"ReactViewGroup.isViewClipped",
|
||||
new ReactNoCrashSoftException(
|
||||
"View missing clipping tag: index="
|
||||
+ index
|
||||
+ " parentNull="
|
||||
+ (parent == null)
|
||||
+ " parentThis="
|
||||
+ (parent == this)));
|
||||
}
|
||||
// fallback - parent *should* be null if the view was removed
|
||||
if (parent == null) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -720,6 +765,10 @@ public class ReactViewGroup extends ViewGroup
|
||||
}
|
||||
}
|
||||
|
||||
private static void setViewClipped(View view, boolean clipped) {
|
||||
view.setTag(R.id.view_clipped, clipped);
|
||||
}
|
||||
|
||||
private int indexOfChildInAllChildren(View child) {
|
||||
final int count = mAllChildrenCount;
|
||||
final View[] childArray = Assertions.assertNotNull(mAllChildren);
|
||||
|
||||
@@ -74,6 +74,9 @@ public class YogaNative {
|
||||
static native void jni_YGNodeStyleSetFlexBasisJNI(long nativePointer, float flexBasis);
|
||||
static native void jni_YGNodeStyleSetFlexBasisPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetFlexBasisAutoJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetFlexBasisMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetFlexBasisFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetFlexBasisStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetMarginJNI(long nativePointer, int edge);
|
||||
static native void jni_YGNodeStyleSetMarginJNI(long nativePointer, int edge, float margin);
|
||||
static native void jni_YGNodeStyleSetMarginPercentJNI(long nativePointer, int edge, float percent);
|
||||
@@ -91,22 +94,40 @@ public class YogaNative {
|
||||
static native void jni_YGNodeStyleSetWidthJNI(long nativePointer, float width);
|
||||
static native void jni_YGNodeStyleSetWidthPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetWidthAutoJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetWidthMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetWidthFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetWidthStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetHeightJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetHeightJNI(long nativePointer, float height);
|
||||
static native void jni_YGNodeStyleSetHeightPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetHeightAutoJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetHeightMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetHeightFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetHeightStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetMinWidthJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinWidthJNI(long nativePointer, float minWidth);
|
||||
static native void jni_YGNodeStyleSetMinWidthPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetMinWidthMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinWidthFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinWidthStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetMinHeightJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinHeightJNI(long nativePointer, float minHeight);
|
||||
static native void jni_YGNodeStyleSetMinHeightPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetMinHeightMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinHeightFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMinHeightStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetMaxWidthJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxWidthJNI(long nativePointer, float maxWidth);
|
||||
static native void jni_YGNodeStyleSetMaxWidthPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetMaxWidthMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxWidthFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxWidthStretchJNI(long nativePointer);
|
||||
static native long jni_YGNodeStyleGetMaxHeightJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxHeightJNI(long nativePointer, float maxheight);
|
||||
static native void jni_YGNodeStyleSetMaxHeightPercentJNI(long nativePointer, float percent);
|
||||
static native void jni_YGNodeStyleSetMaxHeightMaxContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxHeightFitContentJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetMaxHeightStretchJNI(long nativePointer);
|
||||
static native float jni_YGNodeStyleGetAspectRatioJNI(long nativePointer);
|
||||
static native void jni_YGNodeStyleSetAspectRatioJNI(long nativePointer, float aspectRatio);
|
||||
static native float jni_YGNodeStyleGetGapJNI(long nativePointer, int gutter);
|
||||
|
||||
@@ -124,6 +124,12 @@ public abstract class YogaNode implements YogaProps {
|
||||
|
||||
public abstract void setFlexBasisAuto();
|
||||
|
||||
public abstract void setFlexBasisMaxContent();
|
||||
|
||||
public abstract void setFlexBasisFitContent();
|
||||
|
||||
public abstract void setFlexBasisStretch();
|
||||
|
||||
public abstract YogaValue getMargin(YogaEdge edge);
|
||||
|
||||
public abstract void setMargin(YogaEdge edge, float margin);
|
||||
@@ -158,6 +164,12 @@ public abstract class YogaNode implements YogaProps {
|
||||
|
||||
public abstract void setWidthAuto();
|
||||
|
||||
public abstract void setWidthMaxContent();
|
||||
|
||||
public abstract void setWidthFitContent();
|
||||
|
||||
public abstract void setWidthStretch();
|
||||
|
||||
public abstract YogaValue getHeight();
|
||||
|
||||
public abstract void setHeight(float height);
|
||||
@@ -166,30 +178,60 @@ public abstract class YogaNode implements YogaProps {
|
||||
|
||||
public abstract void setHeightAuto();
|
||||
|
||||
public abstract void setHeightMaxContent();
|
||||
|
||||
public abstract void setHeightFitContent();
|
||||
|
||||
public abstract void setHeightStretch();
|
||||
|
||||
public abstract YogaValue getMinWidth();
|
||||
|
||||
public abstract void setMinWidth(float minWidth);
|
||||
|
||||
public abstract void setMinWidthPercent(float percent);
|
||||
|
||||
public abstract void setMinWidthMaxContent();
|
||||
|
||||
public abstract void setMinWidthFitContent();
|
||||
|
||||
public abstract void setMinWidthStretch();
|
||||
|
||||
public abstract YogaValue getMinHeight();
|
||||
|
||||
public abstract void setMinHeight(float minHeight);
|
||||
|
||||
public abstract void setMinHeightPercent(float percent);
|
||||
|
||||
public abstract void setMinHeightMaxContent();
|
||||
|
||||
public abstract void setMinHeightFitContent();
|
||||
|
||||
public abstract void setMinHeightStretch();
|
||||
|
||||
public abstract YogaValue getMaxWidth();
|
||||
|
||||
public abstract void setMaxWidth(float maxWidth);
|
||||
|
||||
public abstract void setMaxWidthPercent(float percent);
|
||||
|
||||
public abstract void setMaxWidthMaxContent();
|
||||
|
||||
public abstract void setMaxWidthFitContent();
|
||||
|
||||
public abstract void setMaxWidthStretch();
|
||||
|
||||
public abstract YogaValue getMaxHeight();
|
||||
|
||||
public abstract void setMaxHeight(float maxheight);
|
||||
|
||||
public abstract void setMaxHeightPercent(float percent);
|
||||
|
||||
public abstract void setMaxHeightMaxContent();
|
||||
|
||||
public abstract void setMaxHeightFitContent();
|
||||
|
||||
public abstract void setMaxHeightStretch();
|
||||
|
||||
public abstract float getAspectRatio();
|
||||
|
||||
public abstract void setAspectRatio(float aspectRatio);
|
||||
|
||||
+84
@@ -373,6 +373,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetFlexBasisAutoJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setFlexBasisMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetFlexBasisMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setFlexBasisFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetFlexBasisFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setFlexBasisStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetFlexBasisStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getMargin(YogaEdge edge) {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetMarginJNI(mNativePointer, edge.intValue()));
|
||||
}
|
||||
@@ -441,6 +453,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetWidthAutoJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setWidthMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetWidthMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setWidthFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetWidthFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setWidthStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetWidthStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getHeight() {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetHeightJNI(mNativePointer));
|
||||
}
|
||||
@@ -457,6 +481,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetHeightAutoJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setHeightMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetHeightMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setHeightFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetHeightFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setHeightStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetHeightStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getMinWidth() {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetMinWidthJNI(mNativePointer));
|
||||
}
|
||||
@@ -469,6 +505,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetMinWidthPercentJNI(mNativePointer, percent);
|
||||
}
|
||||
|
||||
public void setMinWidthMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMinWidthMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMinWidthFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMinWidthFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMinWidthStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetMinWidthStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getMinHeight() {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetMinHeightJNI(mNativePointer));
|
||||
}
|
||||
@@ -481,6 +529,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetMinHeightPercentJNI(mNativePointer, percent);
|
||||
}
|
||||
|
||||
public void setMinHeightMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMinHeightMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMinHeightFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMinHeightFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMinHeightStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetMinHeightStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getMaxWidth() {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetMaxWidthJNI(mNativePointer));
|
||||
}
|
||||
@@ -493,6 +553,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetMaxWidthPercentJNI(mNativePointer, percent);
|
||||
}
|
||||
|
||||
public void setMaxWidthMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxWidthMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMaxWidthFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxWidthFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMaxWidthStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxWidthStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public YogaValue getMaxHeight() {
|
||||
return valueFromLong(YogaNative.jni_YGNodeStyleGetMaxHeightJNI(mNativePointer));
|
||||
}
|
||||
@@ -505,6 +577,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable {
|
||||
YogaNative.jni_YGNodeStyleSetMaxHeightPercentJNI(mNativePointer, percent);
|
||||
}
|
||||
|
||||
public void setMaxHeightMaxContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxHeightMaxContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMaxHeightFitContent() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxHeightFitContentJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public void setMaxHeightStretch() {
|
||||
YogaNative.jni_YGNodeStyleSetMaxHeightStretchJNI(mNativePointer);
|
||||
}
|
||||
|
||||
public float getAspectRatio() {
|
||||
return YogaNative.jni_YGNodeStyleGetAspectRatioJNI(mNativePointer);
|
||||
}
|
||||
|
||||
@@ -15,15 +15,33 @@ public interface YogaProps {
|
||||
|
||||
void setWidthPercent(float percent);
|
||||
|
||||
void setWidthAuto();
|
||||
|
||||
void setWidthMaxContent();
|
||||
|
||||
void setWidthFitContent();
|
||||
|
||||
void setWidthStretch();
|
||||
|
||||
void setMinWidth(float minWidth);
|
||||
|
||||
void setMinWidthPercent(float percent);
|
||||
|
||||
void setMinWidthMaxContent();
|
||||
|
||||
void setMinWidthFitContent();
|
||||
|
||||
void setMinWidthStretch();
|
||||
|
||||
void setMaxWidth(float maxWidth);
|
||||
|
||||
void setMaxWidthPercent(float percent);
|
||||
|
||||
void setWidthAuto();
|
||||
void setMaxWidthMaxContent();
|
||||
|
||||
void setMaxWidthFitContent();
|
||||
|
||||
void setMaxWidthStretch();
|
||||
|
||||
/* Height properties */
|
||||
|
||||
@@ -31,15 +49,33 @@ public interface YogaProps {
|
||||
|
||||
void setHeightPercent(float percent);
|
||||
|
||||
void setHeightAuto();
|
||||
|
||||
void setHeightMaxContent();
|
||||
|
||||
void setHeightFitContent();
|
||||
|
||||
void setHeightStretch();
|
||||
|
||||
void setMinHeight(float minHeight);
|
||||
|
||||
void setMinHeightPercent(float percent);
|
||||
|
||||
void setMinHeightMaxContent();
|
||||
|
||||
void setMinHeightFitContent();
|
||||
|
||||
void setMinHeightStretch();
|
||||
|
||||
void setMaxHeight(float maxHeight);
|
||||
|
||||
void setMaxHeightPercent(float percent);
|
||||
|
||||
void setHeightAuto();
|
||||
void setMaxHeightMaxContent();
|
||||
|
||||
void setMaxHeightFitContent();
|
||||
|
||||
void setMaxHeightStretch();
|
||||
|
||||
/* Margin properties */
|
||||
|
||||
@@ -81,6 +117,12 @@ public interface YogaProps {
|
||||
|
||||
void setFlexBasis(float flexBasis);
|
||||
|
||||
void setFlexBasisMaxContent();
|
||||
|
||||
void setFlexBasisFitContent();
|
||||
|
||||
void setFlexBasisStretch();
|
||||
|
||||
void setFlexDirection(YogaFlexDirection direction);
|
||||
|
||||
void setFlexGrow(float flexGrow);
|
||||
|
||||
@@ -13,7 +13,10 @@ public enum YogaUnit {
|
||||
UNDEFINED(0),
|
||||
POINT(1),
|
||||
PERCENT(2),
|
||||
AUTO(3);
|
||||
AUTO(3),
|
||||
MAX_CONTENT(4),
|
||||
FIT_CONTENT(5),
|
||||
STRETCH(6);
|
||||
|
||||
private final int mIntValue;
|
||||
|
||||
@@ -31,6 +34,9 @@ public enum YogaUnit {
|
||||
case 1: return POINT;
|
||||
case 2: return PERCENT;
|
||||
case 3: return AUTO;
|
||||
case 4: return MAX_CONTENT;
|
||||
case 5: return FIT_CONTENT;
|
||||
case 6: return STRETCH;
|
||||
default: throw new IllegalArgumentException("Unknown enum value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
+92
-7
@@ -429,6 +429,28 @@ static void jni_YGNodeCopyStyleJNI(
|
||||
YGNodeStyleSet##name##Auto(_jlong2YGNodeRef(nativePointer)); \
|
||||
}
|
||||
|
||||
#define YG_NODE_JNI_STYLE_UNIT_PROP_AUTO_INTRINSIC(name) \
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(name) \
|
||||
YG_NODE_JNI_STYLE_UNIT_INTRINSIC(name)
|
||||
|
||||
#define YG_NODE_JNI_STYLE_UNIT_PROP_INTRINSIC(name) \
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP(name) \
|
||||
YG_NODE_JNI_STYLE_UNIT_INTRINSIC(name)
|
||||
|
||||
#define YG_NODE_JNI_STYLE_UNIT_INTRINSIC(name) \
|
||||
static void jni_YGNodeStyleSet##name##MaxContentJNI( \
|
||||
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
|
||||
YGNodeStyleSet##name##MaxContent(_jlong2YGNodeRef(nativePointer)); \
|
||||
} \
|
||||
static void jni_YGNodeStyleSet##name##FitContentJNI( \
|
||||
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
|
||||
YGNodeStyleSet##name##FitContent(_jlong2YGNodeRef(nativePointer)); \
|
||||
} \
|
||||
static void jni_YGNodeStyleSet##name##StretchJNI( \
|
||||
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \
|
||||
YGNodeStyleSet##name##Stretch(_jlong2YGNodeRef(nativePointer)); \
|
||||
}
|
||||
|
||||
#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \
|
||||
static jlong jni_YGNodeStyleGet##name##JNI( \
|
||||
JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jint edge) { \
|
||||
@@ -483,13 +505,13 @@ YG_NODE_JNI_STYLE_PROP(jfloat, float, Flex);
|
||||
YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexGrow);
|
||||
YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexShrink);
|
||||
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(FlexBasis);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(Width);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP(MinWidth);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP(MaxWidth);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(Height);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP(MinHeight);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO_INTRINSIC(FlexBasis);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO_INTRINSIC(Width);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_INTRINSIC(MinWidth);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_INTRINSIC(MaxWidth);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_AUTO_INTRINSIC(Height);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_INTRINSIC(MinHeight);
|
||||
YG_NODE_JNI_STYLE_UNIT_PROP_INTRINSIC(MaxHeight);
|
||||
|
||||
YG_NODE_JNI_STYLE_EDGE_UNIT_PROP_AUTO(Position);
|
||||
|
||||
@@ -870,6 +892,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetFlexBasisAutoJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetFlexBasisAutoJNI},
|
||||
{"jni_YGNodeStyleSetFlexBasisMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetFlexBasisMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetFlexBasisFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetFlexBasisFitContentJNI},
|
||||
{"jni_YGNodeStyleSetFlexBasisStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetFlexBasisStretchJNI},
|
||||
{"jni_YGNodeStyleGetMarginJNI",
|
||||
"(JI)J",
|
||||
(void*)jni_YGNodeStyleGetMarginJNI},
|
||||
@@ -917,6 +948,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetWidthAutoJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetWidthAutoJNI},
|
||||
{"jni_YGNodeStyleSetWidthMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetWidthMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetWidthFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetWidthFitContentJNI},
|
||||
{"jni_YGNodeStyleSetWidthStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetWidthStretchJNI},
|
||||
{"jni_YGNodeStyleGetHeightJNI", "(J)J", (void*)jni_YGNodeStyleGetHeightJNI},
|
||||
{"jni_YGNodeStyleSetHeightJNI",
|
||||
"(JF)V",
|
||||
@@ -927,6 +967,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetHeightAutoJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetHeightAutoJNI},
|
||||
{"jni_YGNodeStyleSetHeightMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetHeightMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetHeightFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetHeightFitContentJNI},
|
||||
{"jni_YGNodeStyleSetHeightStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetHeightStretchJNI},
|
||||
{"jni_YGNodeStyleGetMinWidthJNI",
|
||||
"(J)J",
|
||||
(void*)jni_YGNodeStyleGetMinWidthJNI},
|
||||
@@ -936,6 +985,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetMinWidthPercentJNI",
|
||||
"(JF)V",
|
||||
(void*)jni_YGNodeStyleSetMinWidthPercentJNI},
|
||||
{"jni_YGNodeStyleSetMinWidthMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinWidthMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetMinWidthFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinWidthFitContentJNI},
|
||||
{"jni_YGNodeStyleSetMinWidthStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinWidthStretchJNI},
|
||||
{"jni_YGNodeStyleGetMinHeightJNI",
|
||||
"(J)J",
|
||||
(void*)jni_YGNodeStyleGetMinHeightJNI},
|
||||
@@ -945,6 +1003,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetMinHeightPercentJNI",
|
||||
"(JF)V",
|
||||
(void*)jni_YGNodeStyleSetMinHeightPercentJNI},
|
||||
{"jni_YGNodeStyleSetMinHeightMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinHeightMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetMinHeightFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinHeightFitContentJNI},
|
||||
{"jni_YGNodeStyleSetMinHeightStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMinHeightStretchJNI},
|
||||
{"jni_YGNodeStyleGetMaxWidthJNI",
|
||||
"(J)J",
|
||||
(void*)jni_YGNodeStyleGetMaxWidthJNI},
|
||||
@@ -954,6 +1021,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetMaxWidthPercentJNI",
|
||||
"(JF)V",
|
||||
(void*)jni_YGNodeStyleSetMaxWidthPercentJNI},
|
||||
{"jni_YGNodeStyleSetMaxWidthMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxWidthMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetMaxWidthFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxWidthFitContentJNI},
|
||||
{"jni_YGNodeStyleSetMaxWidthStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxWidthStretchJNI},
|
||||
{"jni_YGNodeStyleGetMaxHeightJNI",
|
||||
"(J)J",
|
||||
(void*)jni_YGNodeStyleGetMaxHeightJNI},
|
||||
@@ -963,6 +1039,15 @@ static JNINativeMethod methods[] = {
|
||||
{"jni_YGNodeStyleSetMaxHeightPercentJNI",
|
||||
"(JF)V",
|
||||
(void*)jni_YGNodeStyleSetMaxHeightPercentJNI},
|
||||
{"jni_YGNodeStyleSetMaxHeightMaxContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxHeightMaxContentJNI},
|
||||
{"jni_YGNodeStyleSetMaxHeightFitContentJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxHeightFitContentJNI},
|
||||
{"jni_YGNodeStyleSetMaxHeightStretchJNI",
|
||||
"(J)V",
|
||||
(void*)jni_YGNodeStyleSetMaxHeightStretchJNI},
|
||||
{"jni_YGNodeStyleGetAspectRatioJNI",
|
||||
"(J)F",
|
||||
(void*)jni_YGNodeStyleGetAspectRatioJNI},
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- tag used to store state of ReactViewGroup subview clipping -->
|
||||
<item type="id" name="view_clipped"/>
|
||||
</resources>
|
||||
@@ -221,6 +221,13 @@ Pod::Spec.new do |s|
|
||||
|
||||
end
|
||||
|
||||
s.subspec "consistency" do |ss|
|
||||
ss.dependency folly_dep_name, folly_version
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.source_files = "react/renderer/consistency/**/*.{m,mm,cpp,h}"
|
||||
ss.header_dir = "react/renderer/consistency"
|
||||
end
|
||||
|
||||
s.subspec "uimanager" do |ss|
|
||||
ss.subspec "consistency" do |sss|
|
||||
sss.dependency folly_dep_name, folly_version
|
||||
|
||||
@@ -125,18 +125,14 @@ void HostAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
|
||||
shouldSendOKResponse = true;
|
||||
isFinishedHandlingRequest = true;
|
||||
} else if (req.method == "FuseboxClient.setClientMetadata") {
|
||||
} else if (req.method == "ReactNativeApplication.enable") {
|
||||
sessionState_.isReactNativeApplicationDomainEnabled = true;
|
||||
fuseboxClientType_ = FuseboxClientType::Fusebox;
|
||||
|
||||
if (sessionState_.isLogDomainEnabled) {
|
||||
sendFuseboxNotice();
|
||||
}
|
||||
|
||||
shouldSendOKResponse = true;
|
||||
isFinishedHandlingRequest = true;
|
||||
} else if (req.method == "ReactNativeApplication.enable") {
|
||||
sessionState_.isReactNativeApplicationDomainEnabled = true;
|
||||
|
||||
frontendChannel_(cdp::jsonNotification(
|
||||
"ReactNativeApplication.metadataUpdated",
|
||||
createHostMetadataPayload(hostMetadata_)));
|
||||
|
||||
@@ -348,21 +348,6 @@ TYPED_TEST(JsiIntegrationPortableTest, ExceptionDuringAddBindingIsIgnored) {
|
||||
EXPECT_TRUE(this->eval("globalThis.foo === 42").getBool());
|
||||
}
|
||||
|
||||
TYPED_TEST(JsiIntegrationPortableTest, FuseboxSetClientMetadata) {
|
||||
this->connect();
|
||||
|
||||
this->expectMessageFromPage(JsonEq(R"({
|
||||
"id": 1,
|
||||
"result": {}
|
||||
})"));
|
||||
|
||||
this->toPage_->sendMessage(R"({
|
||||
"id": 1,
|
||||
"method": "FuseboxClient.setClientMetadata",
|
||||
"params": {}
|
||||
})");
|
||||
}
|
||||
|
||||
TYPED_TEST(JsiIntegrationPortableTest, ReactNativeApplicationEnable) {
|
||||
this->connect();
|
||||
|
||||
|
||||
+4
-9
@@ -45,10 +45,8 @@ namespace {
|
||||
#endif
|
||||
|
||||
NO_DESTROY const std::string TRACK_PREFIX = "Track:";
|
||||
NO_DESTROY const std::string DEFAULT_TRACK_NAME = "# Web Performance";
|
||||
NO_DESTROY const std::string CUSTOM_TRACK_NAME_PREFIX = "# Web Performance: ";
|
||||
|
||||
std::tuple<std::string, std::string_view> parseTrackName(
|
||||
std::tuple<std::optional<std::string>, std::string_view> parseTrackName(
|
||||
const std::string& name) {
|
||||
// Until there's a standard way to pass through track information, parse it
|
||||
// manually, e.g., "Track:Foo:Event name"
|
||||
@@ -58,16 +56,13 @@ std::tuple<std::string, std::string_view> parseTrackName(
|
||||
if (name.starts_with(TRACK_PREFIX)) {
|
||||
const auto trackNameDelimiter = name.find(':', TRACK_PREFIX.length());
|
||||
if (trackNameDelimiter != std::string::npos) {
|
||||
trackName = CUSTOM_TRACK_NAME_PREFIX +
|
||||
name.substr(
|
||||
TRACK_PREFIX.length(),
|
||||
trackNameDelimiter - TRACK_PREFIX.length());
|
||||
trackName = name.substr(
|
||||
TRACK_PREFIX.length(), trackNameDelimiter - TRACK_PREFIX.length());
|
||||
eventName = std::string_view(name).substr(trackNameDelimiter + 1);
|
||||
}
|
||||
}
|
||||
|
||||
auto& trackNameRef = trackName.has_value() ? *trackName : DEFAULT_TRACK_NAME;
|
||||
return std::make_tuple(trackNameRef, eventName);
|
||||
return std::make_tuple(trackName, eventName);
|
||||
}
|
||||
|
||||
class PerformanceObserverWrapper : public jsi::NativeState {
|
||||
|
||||
+30
-8
@@ -41,16 +41,38 @@ bool ParagraphAttributes::operator!=(const ParagraphAttributes& rhs) const {
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const {
|
||||
ParagraphAttributes paragraphAttributes{};
|
||||
return {
|
||||
debugStringConvertibleItem("maximumNumberOfLines", maximumNumberOfLines),
|
||||
debugStringConvertibleItem("ellipsizeMode", ellipsizeMode),
|
||||
debugStringConvertibleItem("textBreakStrategy", textBreakStrategy),
|
||||
debugStringConvertibleItem("adjustsFontSizeToFit", adjustsFontSizeToFit),
|
||||
debugStringConvertibleItem("minimumFontSize", minimumFontSize),
|
||||
debugStringConvertibleItem("maximumFontSize", maximumFontSize),
|
||||
debugStringConvertibleItem("includeFontPadding", includeFontPadding),
|
||||
debugStringConvertibleItem(
|
||||
"android_hyphenationFrequency", android_hyphenationFrequency)};
|
||||
"maximumNumberOfLines",
|
||||
maximumNumberOfLines,
|
||||
paragraphAttributes.maximumNumberOfLines),
|
||||
debugStringConvertibleItem(
|
||||
"ellipsizeMode", ellipsizeMode, paragraphAttributes.ellipsizeMode),
|
||||
debugStringConvertibleItem(
|
||||
"textBreakStrategy",
|
||||
textBreakStrategy,
|
||||
paragraphAttributes.textBreakStrategy),
|
||||
debugStringConvertibleItem(
|
||||
"adjustsFontSizeToFit",
|
||||
adjustsFontSizeToFit,
|
||||
paragraphAttributes.adjustsFontSizeToFit),
|
||||
debugStringConvertibleItem(
|
||||
"minimumFontSize",
|
||||
minimumFontSize,
|
||||
paragraphAttributes.minimumFontSize),
|
||||
debugStringConvertibleItem(
|
||||
"maximumFontSize",
|
||||
maximumFontSize,
|
||||
paragraphAttributes.maximumFontSize),
|
||||
debugStringConvertibleItem(
|
||||
"includeFontPadding",
|
||||
includeFontPadding,
|
||||
paragraphAttributes.includeFontPadding),
|
||||
debugStringConvertibleItem(
|
||||
"android_hyphenationFrequency",
|
||||
android_hyphenationFrequency,
|
||||
paragraphAttributes.android_hyphenationFrequency)};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+77
-29
@@ -197,49 +197,97 @@ TextAttributes TextAttributes::defaultTextAttributes() {
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
SharedDebugStringConvertibleList TextAttributes::getDebugProps() const {
|
||||
const auto& textAttributes = TextAttributes::defaultTextAttributes();
|
||||
return {
|
||||
// Color
|
||||
debugStringConvertibleItem("backgroundColor", backgroundColor),
|
||||
debugStringConvertibleItem("foregroundColor", foregroundColor),
|
||||
debugStringConvertibleItem("opacity", opacity),
|
||||
debugStringConvertibleItem(
|
||||
"backgroundColor", backgroundColor, textAttributes.backgroundColor),
|
||||
debugStringConvertibleItem(
|
||||
"foregroundColor", foregroundColor, textAttributes.foregroundColor),
|
||||
debugStringConvertibleItem("opacity", opacity, textAttributes.opacity),
|
||||
|
||||
// Font
|
||||
debugStringConvertibleItem("fontFamily", fontFamily),
|
||||
debugStringConvertibleItem("fontSize", fontSize),
|
||||
debugStringConvertibleItem("fontSizeMultiplier", fontSizeMultiplier),
|
||||
debugStringConvertibleItem("fontWeight", fontWeight),
|
||||
debugStringConvertibleItem("fontStyle", fontStyle),
|
||||
debugStringConvertibleItem("fontVariant", fontVariant),
|
||||
debugStringConvertibleItem("allowFontScaling", allowFontScaling),
|
||||
debugStringConvertibleItem("dynamicTypeRamp", dynamicTypeRamp),
|
||||
debugStringConvertibleItem("letterSpacing", letterSpacing),
|
||||
debugStringConvertibleItem(
|
||||
"fontFamily", fontFamily, textAttributes.fontFamily),
|
||||
debugStringConvertibleItem("fontSize", fontSize, textAttributes.fontSize),
|
||||
debugStringConvertibleItem(
|
||||
"fontSizeMultiplier",
|
||||
fontSizeMultiplier,
|
||||
textAttributes.fontSizeMultiplier),
|
||||
debugStringConvertibleItem(
|
||||
"fontWeight", fontWeight, textAttributes.fontWeight),
|
||||
debugStringConvertibleItem(
|
||||
"fontStyle", fontStyle, textAttributes.fontStyle),
|
||||
debugStringConvertibleItem(
|
||||
"fontVariant", fontVariant, textAttributes.fontVariant),
|
||||
debugStringConvertibleItem(
|
||||
"allowFontScaling",
|
||||
allowFontScaling,
|
||||
textAttributes.allowFontScaling),
|
||||
debugStringConvertibleItem(
|
||||
"dynamicTypeRamp", dynamicTypeRamp, textAttributes.dynamicTypeRamp),
|
||||
debugStringConvertibleItem(
|
||||
"letterSpacing", letterSpacing, textAttributes.letterSpacing),
|
||||
|
||||
// Paragraph Styles
|
||||
debugStringConvertibleItem("lineHeight", lineHeight),
|
||||
debugStringConvertibleItem("alignment", alignment),
|
||||
debugStringConvertibleItem("baseWritingDirection", baseWritingDirection),
|
||||
debugStringConvertibleItem("lineBreakStrategyIOS", lineBreakStrategy),
|
||||
debugStringConvertibleItem("lineBreakModeIOS", lineBreakMode),
|
||||
debugStringConvertibleItem(
|
||||
"lineHeight", lineHeight, textAttributes.lineHeight),
|
||||
debugStringConvertibleItem(
|
||||
"alignment", alignment, textAttributes.alignment),
|
||||
debugStringConvertibleItem(
|
||||
"baseWritingDirection",
|
||||
baseWritingDirection,
|
||||
textAttributes.baseWritingDirection),
|
||||
debugStringConvertibleItem(
|
||||
"lineBreakStrategyIOS",
|
||||
lineBreakStrategy,
|
||||
textAttributes.lineBreakStrategy),
|
||||
debugStringConvertibleItem(
|
||||
"lineBreakModeIOS", lineBreakMode, textAttributes.lineBreakMode),
|
||||
|
||||
// Decoration
|
||||
debugStringConvertibleItem("textDecorationColor", textDecorationColor),
|
||||
debugStringConvertibleItem(
|
||||
"textDecorationLineType", textDecorationLineType),
|
||||
debugStringConvertibleItem("textDecorationStyle", textDecorationStyle),
|
||||
"textDecorationColor",
|
||||
textDecorationColor,
|
||||
textAttributes.textDecorationColor),
|
||||
debugStringConvertibleItem(
|
||||
"textDecorationLineType",
|
||||
textDecorationLineType,
|
||||
textAttributes.textDecorationLineType),
|
||||
debugStringConvertibleItem(
|
||||
"textDecorationStyle",
|
||||
textDecorationStyle,
|
||||
textAttributes.textDecorationStyle),
|
||||
|
||||
// Shadow
|
||||
debugStringConvertibleItem("textShadowOffset", textShadowOffset),
|
||||
debugStringConvertibleItem("textShadowRadius", textShadowRadius),
|
||||
debugStringConvertibleItem("textShadowColor", textShadowColor),
|
||||
debugStringConvertibleItem(
|
||||
"textShadowOffset",
|
||||
textShadowOffset,
|
||||
textAttributes.textShadowOffset),
|
||||
debugStringConvertibleItem(
|
||||
"textShadowRadius",
|
||||
textShadowRadius,
|
||||
textAttributes.textShadowRadius),
|
||||
debugStringConvertibleItem(
|
||||
"textShadowColor", textShadowColor, textAttributes.textShadowColor),
|
||||
|
||||
// Special
|
||||
debugStringConvertibleItem("isHighlighted", isHighlighted),
|
||||
debugStringConvertibleItem("isPressable", isPressable),
|
||||
debugStringConvertibleItem("layoutDirection", layoutDirection),
|
||||
debugStringConvertibleItem("accessibilityRole", accessibilityRole),
|
||||
debugStringConvertibleItem("role", role),
|
||||
debugStringConvertibleItem(
|
||||
"isHighlighted", isHighlighted, textAttributes.isHighlighted),
|
||||
debugStringConvertibleItem(
|
||||
"isPressable", isPressable, textAttributes.isPressable),
|
||||
debugStringConvertibleItem(
|
||||
"layoutDirection", layoutDirection, textAttributes.layoutDirection),
|
||||
debugStringConvertibleItem(
|
||||
"accessibilityRole",
|
||||
accessibilityRole,
|
||||
textAttributes.accessibilityRole),
|
||||
debugStringConvertibleItem("role", role, textAttributes.role),
|
||||
|
||||
debugStringConvertibleItem("textAlignVertical", textAlignVertical),
|
||||
debugStringConvertibleItem(
|
||||
"textAlignVertical",
|
||||
textAlignVertical,
|
||||
textAttributes.textAlignVertical),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
+18
-1
@@ -30,7 +30,24 @@ void ImageShadowNode::updateStateIfNeeded() {
|
||||
auto newImageSource = getImageSource();
|
||||
const auto& oldImageRequestParams = savedState.getImageRequestParams();
|
||||
const auto& imageProps = getConcreteProps();
|
||||
const auto& newImageRequestParams = ImageRequestParams(imageProps.blurRadius);
|
||||
const auto& newImageRequestParams = ImageRequestParams(
|
||||
imageProps.blurRadius
|
||||
#ifdef ANDROID
|
||||
,
|
||||
imageProps.defaultSource,
|
||||
imageProps.resizeMode,
|
||||
imageProps.resizeMethod,
|
||||
// TODO: should we resizeMultiplier * imageSource.scale ?
|
||||
imageProps.resizeMultiplier,
|
||||
imageProps.shouldNotify,
|
||||
imageProps.overlayColor,
|
||||
imageProps.tintColor,
|
||||
imageProps.fadeDuration,
|
||||
imageProps.progressiveRenderingEnabled,
|
||||
imageProps.loadingIndicatorSource,
|
||||
imageProps.internal_analyticTag
|
||||
#endif
|
||||
);
|
||||
|
||||
if (oldImageSource == newImageSource &&
|
||||
oldImageRequestParams == newImageRequestParams) {
|
||||
|
||||
+8
-6
@@ -538,9 +538,9 @@ void YogaLayoutableShadowNode::setSize(Size size) const {
|
||||
|
||||
auto style = yogaNode_.style();
|
||||
style.setDimension(
|
||||
yoga::Dimension::Width, yoga::StyleLength::points(size.width));
|
||||
yoga::Dimension::Width, yoga::StyleSizeLength::points(size.width));
|
||||
style.setDimension(
|
||||
yoga::Dimension::Height, yoga::StyleLength::points(size.height));
|
||||
yoga::Dimension::Height, yoga::StyleSizeLength::points(size.height));
|
||||
yogaNode_.setStyle(style);
|
||||
yogaNode_.setDirty(true);
|
||||
}
|
||||
@@ -631,16 +631,18 @@ void YogaLayoutableShadowNode::layoutTree(
|
||||
auto ownerHeight = yogaFloatFromFloat(maximumSize.height);
|
||||
|
||||
yogaStyle.setMaxDimension(
|
||||
yoga::Dimension::Width, yoga::StyleLength::points(maximumSize.width));
|
||||
yoga::Dimension::Width, yoga::StyleSizeLength::points(maximumSize.width));
|
||||
|
||||
yogaStyle.setMaxDimension(
|
||||
yoga::Dimension::Height, yoga::StyleLength::points(maximumSize.height));
|
||||
yoga::Dimension::Height,
|
||||
yoga::StyleSizeLength::points(maximumSize.height));
|
||||
|
||||
yogaStyle.setMinDimension(
|
||||
yoga::Dimension::Width, yoga::StyleLength::points(minimumSize.width));
|
||||
yoga::Dimension::Width, yoga::StyleSizeLength::points(minimumSize.width));
|
||||
|
||||
yogaStyle.setMinDimension(
|
||||
yoga::Dimension::Height, yoga::StyleLength::points(minimumSize.height));
|
||||
yoga::Dimension::Height,
|
||||
yoga::StyleSizeLength::points(minimumSize.height));
|
||||
|
||||
auto direction =
|
||||
yogaDirectionFromLayoutDirection(layoutConstraints.layoutDirection);
|
||||
|
||||
@@ -93,18 +93,15 @@ inline yoga::FloatOptional yogaOptionalFloatFromFloat(Float value) {
|
||||
inline std::optional<Float> optionalFloatFromYogaValue(
|
||||
const yoga::Style::Length& length,
|
||||
std::optional<Float> base = {}) {
|
||||
switch (length.unit()) {
|
||||
case yoga::Unit::Undefined:
|
||||
return {};
|
||||
case yoga::Unit::Point:
|
||||
return floatFromYogaOptionalFloat(length.value());
|
||||
case yoga::Unit::Percent:
|
||||
return base.has_value()
|
||||
? std::optional<Float>(
|
||||
base.value() * floatFromYogaOptionalFloat(length.value()))
|
||||
: std::optional<Float>();
|
||||
case yoga::Unit::Auto:
|
||||
return {};
|
||||
if (length.isPoints()) {
|
||||
return floatFromYogaOptionalFloat(length.value());
|
||||
} else if (length.isPercent()) {
|
||||
return base.has_value()
|
||||
? std::optional<Float>(
|
||||
base.value() * floatFromYogaOptionalFloat(length.value()))
|
||||
: std::optional<Float>();
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,6 +444,47 @@ inline void fromRawValue(
|
||||
LOG(ERROR) << "Could not parse yoga::Display: " << stringValue;
|
||||
}
|
||||
|
||||
inline void fromRawValue(
|
||||
const PropsParserContext& /*context*/,
|
||||
const RawValue& value,
|
||||
yoga::Style::SizeLength& result) {
|
||||
if (value.hasType<Float>()) {
|
||||
result = yoga::StyleSizeLength::points((float)value);
|
||||
return;
|
||||
} else if (value.hasType<std::string>()) {
|
||||
const auto stringValue = (std::string)value;
|
||||
if (stringValue == "auto") {
|
||||
result = yoga::StyleSizeLength::ofAuto();
|
||||
return;
|
||||
} else if (stringValue == "max-content") {
|
||||
result = yoga::StyleSizeLength::ofMaxContent();
|
||||
return;
|
||||
} else if (stringValue == "stretch") {
|
||||
result = yoga::StyleSizeLength::ofStretch();
|
||||
return;
|
||||
} else if (stringValue == "fit-content") {
|
||||
result = yoga::StyleSizeLength::ofFitContent();
|
||||
return;
|
||||
} else {
|
||||
if (stringValue.back() == '%') {
|
||||
auto tryValue = folly::tryTo<float>(
|
||||
std::string_view(stringValue).substr(0, stringValue.length() - 1));
|
||||
if (tryValue.hasValue()) {
|
||||
result = yoga::StyleSizeLength::percent(tryValue.value());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
auto tryValue = folly::tryTo<float>(stringValue);
|
||||
if (tryValue.hasValue()) {
|
||||
result = yoga::StyleSizeLength::points(tryValue.value());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = yoga::StyleSizeLength::undefined();
|
||||
}
|
||||
|
||||
inline void fromRawValue(
|
||||
const PropsParserContext& context,
|
||||
const RawValue& value,
|
||||
@@ -1376,15 +1414,36 @@ inline std::string toString(const yoga::Display& value) {
|
||||
}
|
||||
|
||||
inline std::string toString(const yoga::Style::Length& length) {
|
||||
switch (length.unit()) {
|
||||
case yoga::Unit::Undefined:
|
||||
return "undefined";
|
||||
case yoga::Unit::Point:
|
||||
return std::to_string(length.value().unwrap());
|
||||
case yoga::Unit::Percent:
|
||||
return std::to_string(length.value().unwrap()) + "%";
|
||||
case yoga::Unit::Auto:
|
||||
return "auto";
|
||||
if (length.isUndefined()) {
|
||||
return "undefined";
|
||||
} else if (length.isAuto()) {
|
||||
return "auto";
|
||||
} else if (length.isPoints()) {
|
||||
return std::to_string(length.value().unwrap());
|
||||
} else if (length.isPercent()) {
|
||||
return std::to_string(length.value().unwrap()) + "%";
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string toString(const yoga::Style::SizeLength& length) {
|
||||
if (length.isUndefined()) {
|
||||
return "undefined";
|
||||
} else if (length.isAuto()) {
|
||||
return "auto";
|
||||
} else if (length.isPoints()) {
|
||||
return std::to_string(length.value().unwrap());
|
||||
} else if (length.isPercent()) {
|
||||
return std::to_string(length.value().unwrap()) + "%";
|
||||
} else if (length.isMaxContent()) {
|
||||
return "max-content";
|
||||
} else if (length.isFitContent()) {
|
||||
return "fit-content";
|
||||
} else if (length.isStretch()) {
|
||||
return "stretch";
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -77,8 +77,8 @@ class LayoutTest : public ::testing::Test {
|
||||
auto &props = *sharedProps;
|
||||
props.layoutConstraints = LayoutConstraints{{0,0}, {500, 500}};
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -90,8 +90,8 @@ class LayoutTest : public ::testing::Test {
|
||||
auto &props = *sharedProps;
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(50));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -105,8 +105,8 @@ class LayoutTest : public ::testing::Test {
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(10));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(10));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(30));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(90));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(30));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(90));
|
||||
|
||||
if (testCase == TRANSFORM_SCALE) {
|
||||
props.transform = props.transform * Transform::Scale(2, 2, 1);
|
||||
@@ -138,8 +138,8 @@ class LayoutTest : public ::testing::Test {
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(10));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(10));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(110));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(20));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(110));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(20));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -153,8 +153,8 @@ class LayoutTest : public ::testing::Test {
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(70));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(-50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(30));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(60));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(30));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(60));
|
||||
return sharedProps;
|
||||
})
|
||||
}),
|
||||
@@ -168,8 +168,8 @@ class LayoutTest : public ::testing::Test {
|
||||
yogaStyle.setPositionType(yoga::PositionType::Absolute);
|
||||
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(-60));
|
||||
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(50));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(70));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(20));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(70));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(20));
|
||||
return sharedProps;
|
||||
})
|
||||
})
|
||||
|
||||
+19
-4
@@ -15,14 +15,29 @@
|
||||
|
||||
#include <react/renderer/debug/DebugStringConvertible.h>
|
||||
#include <react/renderer/debug/DebugStringConvertibleItem.h>
|
||||
#include <react/utils/FloatComparison.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
|
||||
inline SharedDebugStringConvertible debugStringConvertibleItem(
|
||||
const std::string& name,
|
||||
float value,
|
||||
float defaultValue = {}) {
|
||||
if (floatEquality(value, defaultValue)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<DebugStringConvertibleItem>(
|
||||
name, facebook::react::toString(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline SharedDebugStringConvertible
|
||||
debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
|
||||
inline SharedDebugStringConvertible debugStringConvertibleItem(
|
||||
const std::string& name,
|
||||
T value,
|
||||
T defaultValue = {}) {
|
||||
if (value == defaultValue) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -33,7 +48,7 @@ debugStringConvertibleItem(std::string name, T value, T defaultValue = {}) {
|
||||
|
||||
template <typename T>
|
||||
inline SharedDebugStringConvertible debugStringConvertibleItem(
|
||||
std::string name,
|
||||
const std::string& name,
|
||||
std::optional<T> value,
|
||||
T defaultValue = {}) {
|
||||
if (!value.has_value()) {
|
||||
@@ -54,7 +69,7 @@ inline SharedDebugStringConvertibleList operator+(
|
||||
}
|
||||
|
||||
inline SharedDebugStringConvertible debugStringConvertibleItem(
|
||||
std::string name,
|
||||
const std::string& name,
|
||||
DebugStringConvertible value,
|
||||
std::string defaultValue) {
|
||||
return debugStringConvertibleItem(
|
||||
|
||||
@@ -16,7 +16,7 @@ add_compile_options(
|
||||
|
||||
file(GLOB react_render_imagemanager_SRC CONFIGURE_DEPENDS
|
||||
*.cpp
|
||||
platform/cxx/react/renderer/imagemanager/*.cpp)
|
||||
platform/android/react/renderer/imagemanager/*.cpp)
|
||||
|
||||
add_library(react_render_imagemanager
|
||||
OBJECT
|
||||
@@ -25,7 +25,7 @@ add_library(react_render_imagemanager
|
||||
target_include_directories(react_render_imagemanager
|
||||
PUBLIC
|
||||
${REACT_COMMON_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platform/cxx/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/platform/android/
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <react/renderer/graphics/Float.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class ImageRequestParams {
|
||||
public:
|
||||
ImageRequestParams() = default;
|
||||
ImageRequestParams(Float blurRadius) : blurRadius(blurRadius) {}
|
||||
|
||||
Float blurRadius{};
|
||||
|
||||
bool operator==(const ImageRequestParams& rhs) const {
|
||||
return this->blurRadius == rhs.blurRadius;
|
||||
}
|
||||
|
||||
bool operator!=(const ImageRequestParams& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <react/renderer/graphics/Color.h>
|
||||
#include <react/renderer/graphics/Float.h>
|
||||
#include <react/renderer/imagemanager/primitives.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class ImageRequestParams {
|
||||
public:
|
||||
ImageRequestParams() = default;
|
||||
ImageRequestParams(
|
||||
Float blurRadius,
|
||||
ImageSource defaultSource,
|
||||
ImageResizeMode resizeMode,
|
||||
std::string resizeMethod,
|
||||
Float resizeMultiplier,
|
||||
bool shouldNotify,
|
||||
SharedColor overlayColor,
|
||||
SharedColor tintColor,
|
||||
Float fadeDuration,
|
||||
bool progressiveRenderingEnabled,
|
||||
ImageSource loadingIndicatorSource,
|
||||
std::string analyticTag)
|
||||
: blurRadius(blurRadius),
|
||||
defaultSource(std::move(defaultSource)),
|
||||
resizeMode(resizeMode),
|
||||
resizeMethod(std::move(resizeMethod)),
|
||||
resizeMultiplier(resizeMultiplier),
|
||||
shouldNotify(shouldNotify),
|
||||
overlayColor(overlayColor),
|
||||
tintColor(tintColor),
|
||||
fadeDuration(fadeDuration),
|
||||
progressiveRenderingEnabled(progressiveRenderingEnabled),
|
||||
loadingIndicatorSource(std::move(loadingIndicatorSource)),
|
||||
analyticTag(std::move(analyticTag)) {}
|
||||
|
||||
Float blurRadius{};
|
||||
ImageSource defaultSource{};
|
||||
ImageResizeMode resizeMode{ImageResizeMode::Stretch};
|
||||
std::string resizeMethod{};
|
||||
Float resizeMultiplier{};
|
||||
bool shouldNotify{};
|
||||
SharedColor overlayColor{};
|
||||
SharedColor tintColor{};
|
||||
Float fadeDuration{};
|
||||
bool progressiveRenderingEnabled{};
|
||||
ImageSource loadingIndicatorSource{};
|
||||
std::string analyticTag{};
|
||||
|
||||
bool operator==(const ImageRequestParams& rhs) const {
|
||||
return std::tie(
|
||||
this->blurRadius,
|
||||
this->defaultSource,
|
||||
this->resizeMode,
|
||||
this->resizeMethod,
|
||||
this->resizeMultiplier,
|
||||
this->shouldNotify,
|
||||
this->overlayColor,
|
||||
this->tintColor,
|
||||
this->fadeDuration,
|
||||
this->progressiveRenderingEnabled,
|
||||
this->loadingIndicatorSource,
|
||||
this->analyticTag) ==
|
||||
std::tie(
|
||||
rhs.blurRadius,
|
||||
rhs.defaultSource,
|
||||
rhs.resizeMode,
|
||||
rhs.resizeMethod,
|
||||
rhs.resizeMultiplier,
|
||||
rhs.shouldNotify,
|
||||
rhs.overlayColor,
|
||||
rhs.tintColor,
|
||||
rhs.fadeDuration,
|
||||
rhs.progressiveRenderingEnabled,
|
||||
rhs.loadingIndicatorSource,
|
||||
rhs.analyticTag);
|
||||
}
|
||||
|
||||
bool operator!=(const ImageRequestParams& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <react/renderer/core/graphicsConversions.h>
|
||||
#include <react/renderer/imagemanager/ImageRequestParams.h>
|
||||
#include <react/renderer/imagemanager/primitives.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
inline std::string toString(const ImageResizeMode& value) {
|
||||
switch (value) {
|
||||
case ImageResizeMode::Cover:
|
||||
return "cover";
|
||||
case ImageResizeMode::Contain:
|
||||
return "contain";
|
||||
case ImageResizeMode::Stretch:
|
||||
return "stretch";
|
||||
case ImageResizeMode::Center:
|
||||
return "center";
|
||||
case ImageResizeMode::Repeat:
|
||||
return "repeat";
|
||||
case ImageResizeMode::None:
|
||||
return "none";
|
||||
}
|
||||
}
|
||||
|
||||
constexpr static MapBuffer::Key IS_KEY_URI = 0;
|
||||
constexpr static MapBuffer::Key IS_KEY_DEFAULT_SRC = 1;
|
||||
constexpr static MapBuffer::Key IS_KEY_RESIZE_MODE = 2;
|
||||
constexpr static MapBuffer::Key IS_KEY_RESIZE_METHOD = 3;
|
||||
constexpr static MapBuffer::Key IS_KEY_BLUR_RADIUS = 4;
|
||||
constexpr static MapBuffer::Key IS_KEY_VIEW_WIDTH = 5;
|
||||
constexpr static MapBuffer::Key IS_KEY_VIEW_HEIGHT = 6;
|
||||
constexpr static MapBuffer::Key IS_KEY_RESIZE_MULTIPLIER = 7;
|
||||
constexpr static MapBuffer::Key IS_KEY_SHOULD_NOTIFY_LOAD_EVENTS = 8;
|
||||
constexpr static MapBuffer::Key IS_KEY_OVERLAY_COLOR = 9;
|
||||
constexpr static MapBuffer::Key IS_KEY_TINT_COLOR = 10;
|
||||
constexpr static MapBuffer::Key IS_KEY_FADE_DURATION = 11;
|
||||
constexpr static MapBuffer::Key IS_KEY_PROGRESSIVE_RENDERING_ENABLED = 12;
|
||||
constexpr static MapBuffer::Key IS_KEY_LOADING_INDICATOR_SRC = 13;
|
||||
constexpr static MapBuffer::Key IS_KEY_ANALYTIC_TAG = 14;
|
||||
|
||||
inline void serializeImageSource(
|
||||
MapBufferBuilder& builder,
|
||||
const ImageSource& imageSource) {
|
||||
builder.putString(IS_KEY_URI, imageSource.uri);
|
||||
builder.putDouble(IS_KEY_VIEW_WIDTH, imageSource.size.width);
|
||||
builder.putDouble(IS_KEY_VIEW_HEIGHT, imageSource.size.height);
|
||||
}
|
||||
|
||||
inline void serializeImageRequestParams(
|
||||
MapBufferBuilder& builder,
|
||||
const ImageRequestParams& imageRequestParams) {
|
||||
builder.putString(IS_KEY_DEFAULT_SRC, imageRequestParams.defaultSource.uri);
|
||||
builder.putString(
|
||||
IS_KEY_RESIZE_MODE, toString(imageRequestParams.resizeMode));
|
||||
builder.putString(IS_KEY_RESIZE_METHOD, imageRequestParams.resizeMethod);
|
||||
builder.putDouble(IS_KEY_BLUR_RADIUS, imageRequestParams.blurRadius);
|
||||
builder.putDouble(
|
||||
IS_KEY_RESIZE_MULTIPLIER, imageRequestParams.resizeMultiplier);
|
||||
builder.putBool(
|
||||
IS_KEY_SHOULD_NOTIFY_LOAD_EVENTS, imageRequestParams.shouldNotify);
|
||||
if (isColorMeaningful(imageRequestParams.overlayColor)) {
|
||||
builder.putInt(
|
||||
IS_KEY_OVERLAY_COLOR, toAndroidRepr(imageRequestParams.overlayColor));
|
||||
}
|
||||
if (isColorMeaningful(imageRequestParams.tintColor)) {
|
||||
builder.putInt(
|
||||
IS_KEY_TINT_COLOR, toAndroidRepr(imageRequestParams.tintColor));
|
||||
}
|
||||
builder.putDouble(IS_KEY_FADE_DURATION, imageRequestParams.fadeDuration);
|
||||
builder.putBool(
|
||||
IS_KEY_PROGRESSIVE_RENDERING_ENABLED,
|
||||
imageRequestParams.progressiveRenderingEnabled);
|
||||
builder.putString(
|
||||
IS_KEY_LOADING_INDICATOR_SRC,
|
||||
imageRequestParams.loadingIndicatorSource.uri);
|
||||
builder.putString(IS_KEY_ANALYTIC_TAG, imageRequestParams.analyticTag);
|
||||
}
|
||||
|
||||
inline MapBuffer serializeImageRequest(
|
||||
const ImageSource& imageSource,
|
||||
const ImageRequestParams& imageRequestParams) {
|
||||
auto builder = MapBufferBuilder();
|
||||
serializeImageSource(builder, imageSource);
|
||||
serializeImageRequestParams(builder, imageRequestParams);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
+117
-184
@@ -45,17 +45,22 @@ static SharedViewProps nonFlattenedDefaultProps(
|
||||
static ShadowNode::Shared makeNode(
|
||||
const ComponentDescriptor& componentDescriptor,
|
||||
int tag,
|
||||
const ShadowNode::ListOfShared& children,
|
||||
std::shared_ptr<ShadowNode::ListOfShared> children,
|
||||
bool flattened = false) {
|
||||
auto props = flattened ? generateDefaultProps(componentDescriptor)
|
||||
: nonFlattenedDefaultProps(componentDescriptor);
|
||||
|
||||
return componentDescriptor.createShadowNode(
|
||||
ShadowNodeFragment{
|
||||
props, std::make_shared<ShadowNode::ListOfShared>(children)},
|
||||
ShadowNodeFragment{std::move(props), std::move(children)},
|
||||
componentDescriptor.createFamily({tag, SurfaceId(1), nullptr}));
|
||||
}
|
||||
|
||||
static std::shared_ptr<ShadowNode::ListOfShared> listOfChildren(
|
||||
std::initializer_list<ShadowNode::Shared> list) {
|
||||
return std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{list});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reordering of views with the same parent:
|
||||
*
|
||||
@@ -117,25 +122,20 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
|
||||
auto shadowNodeV1 = viewComponentDescriptor.createShadowNode(
|
||||
ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childB, childC, childD})},
|
||||
listOfChildren({childB, childC, childD})},
|
||||
family);
|
||||
auto shadowNodeV2 = shadowNodeV1->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childA, childB, childC, childD})});
|
||||
listOfChildren({childA, childB, childC, childD})});
|
||||
auto shadowNodeV3 = shadowNodeV2->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childB, childC, childD})});
|
||||
listOfChildren({childB, childC, childD})});
|
||||
auto shadowNodeV4 = shadowNodeV3->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childB, childD, childE})});
|
||||
listOfChildren({childB, childD, childE})});
|
||||
auto shadowNodeV5 = shadowNodeV4->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childB, childA, childE, childC})});
|
||||
listOfChildren({childB, childA, childE, childC})});
|
||||
auto shadowNodeV6 = shadowNodeV5->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
|
||||
@@ -157,38 +157,31 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
|
||||
auto rootNodeV1 = std::static_pointer_cast<const RootShadowNode>(
|
||||
emptyRootNode->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV1})}));
|
||||
listOfChildren({shadowNodeV1})}));
|
||||
auto rootNodeV2 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV1->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV2})}));
|
||||
listOfChildren({shadowNodeV2})}));
|
||||
auto rootNodeV3 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV2->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV3})}));
|
||||
listOfChildren({shadowNodeV3})}));
|
||||
auto rootNodeV4 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV3->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV4})}));
|
||||
listOfChildren({shadowNodeV4})}));
|
||||
auto rootNodeV5 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV4->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV5})}));
|
||||
listOfChildren({shadowNodeV5})}));
|
||||
auto rootNodeV6 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV5->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV6})}));
|
||||
listOfChildren({shadowNodeV6})}));
|
||||
auto rootNodeV7 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV6->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV7})}));
|
||||
listOfChildren({shadowNodeV7})}));
|
||||
|
||||
// Layout
|
||||
std::vector<const LayoutableShadowNode*> affectedLayoutableNodesV1{};
|
||||
@@ -289,7 +282,6 @@ TEST(MountingTest, testReorderingInstructionGeneration) {
|
||||
|
||||
// Calculating mutations.
|
||||
auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4);
|
||||
LOG(ERROR) << "Num mutations IN OLD TEST mutations3: " << mutations3.size();
|
||||
|
||||
// The order and exact mutation instructions here may change at any time.
|
||||
// This test just ensures that any changes are intentional.
|
||||
@@ -425,172 +417,107 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
|
||||
auto family =
|
||||
viewComponentDescriptor.createFamily({10, SurfaceId(1), nullptr});
|
||||
|
||||
auto reparentedViewA = makeNode(
|
||||
viewComponentDescriptor,
|
||||
1000,
|
||||
ShadowNode::ListOfShared{
|
||||
childC->clone({}), childA->clone({}), childB->clone({})});
|
||||
auto reparentedViewA_ = makeNode(
|
||||
viewComponentDescriptor, 1000, listOfChildren({childC, childA, childB}));
|
||||
auto reparentedViewA = reparentedViewA_->clone(
|
||||
ShadowNodeFragment{nonFlattenedDefaultProps(viewComponentDescriptor)});
|
||||
auto reparentedViewB = makeNode(
|
||||
viewComponentDescriptor,
|
||||
2000,
|
||||
ShadowNode::ListOfShared{
|
||||
childF->clone({}), childE->clone({}), childD->clone({})});
|
||||
viewComponentDescriptor, 2000, listOfChildren({childF, childE, childD}));
|
||||
|
||||
// Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened]
|
||||
auto shadowNodeV1 = viewComponentDescriptor.createShadowNode(
|
||||
ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
|
||||
listOfChildren({childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childH->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
reparentedViewA->clone(
|
||||
{})})})})})})})})})})},
|
||||
listOfChildren({reparentedViewA_})})})})})})})})})},
|
||||
family);
|
||||
|
||||
// Root -> G* -> H* -> I -> J -> A* [nodes with * are _not_ flattened]
|
||||
// Force an update with A with new props
|
||||
auto shadowNodeV2 = shadowNodeV1->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
|
||||
listOfChildren({childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childH->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
|
||||
childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
reparentedViewA->clone(
|
||||
{})})})})})})})})})})});
|
||||
listOfChildren({childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({reparentedViewA})})})})})})})})})});
|
||||
|
||||
// Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened]
|
||||
auto shadowNodeV3 = shadowNodeV2->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
|
||||
listOfChildren({childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childH->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
|
||||
childI->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
reparentedViewA->clone(
|
||||
{})})})})})})})})})})});
|
||||
listOfChildren({reparentedViewA})})})})})})})})})});
|
||||
|
||||
// The view is reparented 1 level down with a different sibling
|
||||
// Root -> G* -> H* -> I* -> J -> [B*, A*] [nodes with * are _not_ flattened]
|
||||
auto shadowNodeV4 = shadowNodeV3->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
|
||||
listOfChildren({childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childH->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
|
||||
childI->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
reparentedViewB->clone({}),
|
||||
reparentedViewA->clone(
|
||||
{})})})})})})})})})})});
|
||||
listOfChildren({childI->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childJ->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren(
|
||||
{reparentedViewB, reparentedViewA})})})})})})})})})});
|
||||
|
||||
// The view is reparented 1 level further down with its order with the sibling
|
||||
// swapped
|
||||
// Root -> G* -> H* -> I* -> J* -> [A*, B*] [nodes with * are _not_ flattened]
|
||||
auto shadowNodeV5 = shadowNodeV4->clone(ShadowNodeFragment{
|
||||
generateDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childG->clone(ShadowNodeFragment{
|
||||
listOfChildren({childG->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childH->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{childH->clone(ShadowNodeFragment{
|
||||
listOfChildren({childI->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
listOfChildren({childJ->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(ShadowNode::ListOfShared{
|
||||
childI->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(viewComponentDescriptor),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
childJ->clone(ShadowNodeFragment{
|
||||
nonFlattenedDefaultProps(
|
||||
viewComponentDescriptor),
|
||||
std::make_shared<
|
||||
ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{
|
||||
reparentedViewA->clone({}),
|
||||
reparentedViewB->clone(
|
||||
{})})})})})})})})})})});
|
||||
listOfChildren(
|
||||
{reparentedViewA, reparentedViewB})})})})})})})})})});
|
||||
|
||||
// Injecting a tree into the root node.
|
||||
auto rootNodeV1 = std::static_pointer_cast<const RootShadowNode>(
|
||||
emptyRootNode->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV1})}));
|
||||
listOfChildren({shadowNodeV1})}));
|
||||
auto rootNodeV2 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV1->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV2})}));
|
||||
listOfChildren({shadowNodeV2})}));
|
||||
auto rootNodeV3 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV2->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV3})}));
|
||||
listOfChildren({shadowNodeV3})}));
|
||||
auto rootNodeV4 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV3->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV4})}));
|
||||
listOfChildren({shadowNodeV4})}));
|
||||
auto rootNodeV5 = std::static_pointer_cast<const RootShadowNode>(
|
||||
rootNodeV4->ShadowNode::clone(ShadowNodeFragment{
|
||||
ShadowNodeFragment::propsPlaceholder(),
|
||||
std::make_shared<ShadowNode::ListOfShared>(
|
||||
ShadowNode::ListOfShared{shadowNodeV5})}));
|
||||
listOfChildren({shadowNodeV5})}));
|
||||
|
||||
// Layout
|
||||
std::vector<const LayoutableShadowNode*> affectedLayoutableNodesV1{};
|
||||
@@ -626,33 +553,38 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
|
||||
// Calculating mutations.
|
||||
auto mutations1 = calculateShadowViewMutations(*rootNodeV1, *rootNodeV2);
|
||||
|
||||
EXPECT_EQ(mutations1.size(), 5);
|
||||
EXPECT_EQ(mutations1.size(), 6);
|
||||
EXPECT_EQ(mutations1[0].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations1[0].oldChildShadowView.tag, 106);
|
||||
EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations1[1].oldChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations1[2].newChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations1[3].newChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations1[0].oldChildShadowView.tag, childG->getTag());
|
||||
EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations1[1].oldChildShadowView.tag, reparentedViewA->getTag());
|
||||
// This is incorrect! ChildH does not exist yet at this point
|
||||
EXPECT_EQ(mutations1[1].parentShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations1[2].oldChildShadowView.tag, reparentedViewA->getTag());
|
||||
EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations1[3].newChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations1[4].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations1[4].newChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations1[4].newChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations1[5].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations1[5].newChildShadowView.tag, reparentedViewA->getTag());
|
||||
|
||||
auto mutations2 = calculateShadowViewMutations(*rootNodeV2, *rootNodeV3);
|
||||
|
||||
EXPECT_EQ(mutations2.size(), 5);
|
||||
EXPECT_EQ(mutations2[0].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations2[0].oldChildShadowView.tag, 106);
|
||||
EXPECT_EQ(mutations2[0].oldChildShadowView.tag, childG->getTag());
|
||||
EXPECT_EQ(mutations2[0].parentShadowView.tag, emptyRootNode->getTag());
|
||||
EXPECT_EQ(mutations2[1].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations2[1].oldChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations2[1].oldChildShadowView.tag, reparentedViewA->getTag());
|
||||
EXPECT_EQ(mutations2[2].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations2[2].oldChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations2[2].oldChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(
|
||||
mutations2[3].type,
|
||||
ShadowViewMutation::Delete); // correct, 107 is removed from tree entirely
|
||||
EXPECT_EQ(mutations2[3].oldChildShadowView.tag, 107);
|
||||
ShadowViewMutation::Delete); // correct, H is removed from tree entirely
|
||||
EXPECT_EQ(mutations2[3].oldChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations2[4].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations2[4].newChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations2[4].newChildShadowView.tag, reparentedViewA->getTag());
|
||||
|
||||
auto mutations3 = calculateShadowViewMutations(*rootNodeV3, *rootNodeV4);
|
||||
|
||||
@@ -661,57 +593,58 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
|
||||
|
||||
EXPECT_EQ(mutations3.size(), 15);
|
||||
EXPECT_EQ(mutations3[0].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations3[0].oldChildShadowView.tag, 106);
|
||||
EXPECT_EQ(mutations3[0].oldChildShadowView.tag, childG->getTag());
|
||||
EXPECT_EQ(mutations3[0].parentShadowView.tag, emptyRootNode->getTag());
|
||||
EXPECT_EQ(mutations3[1].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations3[1].oldChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations3[1].oldChildShadowView.tag, reparentedViewA->getTag());
|
||||
EXPECT_EQ(mutations3[2].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[2].newChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations3[2].newChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations3[3].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[3].newChildShadowView.tag, 2000);
|
||||
EXPECT_EQ(mutations3[3].newChildShadowView.tag, reparentedViewB->getTag());
|
||||
EXPECT_EQ(mutations3[4].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[4].newChildShadowView.tag, 108);
|
||||
EXPECT_EQ(mutations3[4].newChildShadowView.tag, childI->getTag());
|
||||
EXPECT_EQ(mutations3[5].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[5].newChildShadowView.tag, 105);
|
||||
EXPECT_EQ(mutations3[5].newChildShadowView.tag, childF->getTag());
|
||||
EXPECT_EQ(mutations3[6].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[6].newChildShadowView.tag, 104);
|
||||
EXPECT_EQ(mutations3[6].newChildShadowView.tag, childE->getTag());
|
||||
EXPECT_EQ(mutations3[7].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations3[7].newChildShadowView.tag, 103);
|
||||
EXPECT_EQ(mutations3[7].newChildShadowView.tag, childD->getTag());
|
||||
EXPECT_EQ(mutations3[8].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[8].newChildShadowView.tag, 105);
|
||||
EXPECT_EQ(mutations3[8].newChildShadowView.tag, childF->getTag());
|
||||
EXPECT_EQ(mutations3[9].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[9].newChildShadowView.tag, 104);
|
||||
EXPECT_EQ(mutations3[9].newChildShadowView.tag, childE->getTag());
|
||||
EXPECT_EQ(mutations3[10].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[10].newChildShadowView.tag, 103);
|
||||
EXPECT_EQ(mutations3[10].newChildShadowView.tag, childD->getTag());
|
||||
EXPECT_EQ(mutations3[11].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[11].newChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations3[11].newChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations3[12].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[12].newChildShadowView.tag, 108);
|
||||
EXPECT_EQ(mutations3[12].newChildShadowView.tag, childI->getTag());
|
||||
EXPECT_EQ(mutations3[13].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[13].newChildShadowView.tag, 2000);
|
||||
EXPECT_EQ(mutations3[13].newChildShadowView.tag, reparentedViewB->getTag());
|
||||
EXPECT_EQ(mutations3[14].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations3[14].newChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations3[14].newChildShadowView.tag, reparentedViewA->getTag());
|
||||
|
||||
auto mutations4 = calculateShadowViewMutations(*rootNodeV4, *rootNodeV5);
|
||||
|
||||
EXPECT_EQ(mutations4.size(), 9);
|
||||
EXPECT_EQ(mutations4[0].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations4[0].oldChildShadowView.tag, 106);
|
||||
EXPECT_EQ(mutations4[0].oldChildShadowView.tag, childG->getTag());
|
||||
EXPECT_EQ(mutations4[1].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations4[1].oldChildShadowView.tag, 107);
|
||||
EXPECT_EQ(mutations4[1].oldChildShadowView.tag, childH->getTag());
|
||||
EXPECT_EQ(mutations4[2].type, ShadowViewMutation::Update);
|
||||
EXPECT_EQ(mutations4[2].oldChildShadowView.tag, 108);
|
||||
EXPECT_EQ(mutations4[2].oldChildShadowView.tag, childI->getTag());
|
||||
EXPECT_EQ(mutations4[3].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations4[3].oldChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations4[3].oldChildShadowView.tag, reparentedViewA->getTag());
|
||||
EXPECT_EQ(mutations4[4].type, ShadowViewMutation::Remove);
|
||||
EXPECT_EQ(mutations4[4].oldChildShadowView.tag, 2000);
|
||||
EXPECT_EQ(mutations4[4].oldChildShadowView.tag, reparentedViewB->getTag());
|
||||
EXPECT_EQ(mutations4[5].type, ShadowViewMutation::Create);
|
||||
EXPECT_EQ(mutations4[5].newChildShadowView.tag, 109);
|
||||
EXPECT_EQ(mutations4[5].newChildShadowView.tag, childJ->getTag());
|
||||
EXPECT_EQ(mutations4[6].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations4[6].newChildShadowView.tag, 109);
|
||||
EXPECT_EQ(mutations4[6].newChildShadowView.tag, childJ->getTag());
|
||||
EXPECT_EQ(mutations4[7].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations4[7].newChildShadowView.tag, 1000);
|
||||
EXPECT_EQ(mutations4[7].newChildShadowView.tag, reparentedViewA->getTag());
|
||||
EXPECT_EQ(mutations4[8].type, ShadowViewMutation::Insert);
|
||||
EXPECT_EQ(mutations4[8].newChildShadowView.tag, 2000);
|
||||
EXPECT_EQ(mutations4[8].newChildShadowView.tag, reparentedViewB->getTag());
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+10
-10
@@ -87,8 +87,8 @@ class PointerEventsProcessorTest : public ::testing::Test {
|
||||
listenToAllPointerEvents(props);
|
||||
props.layoutConstraints = LayoutConstraints{{0,0}, {500, 500}};
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(400));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(400));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(400));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(400));
|
||||
yogaStyle.setDisplay(yoga::Display::Flex);
|
||||
yogaStyle.setFlexDirection(yoga::FlexDirection::Row);
|
||||
yogaStyle.setAlignItems(yoga::Align::Center);
|
||||
@@ -109,8 +109,8 @@ class PointerEventsProcessorTest : public ::testing::Test {
|
||||
yogaStyle.setFlexDirection(yoga::FlexDirection::Column);
|
||||
yogaStyle.setAlignItems(yoga::Align::FlexEnd);
|
||||
yogaStyle.setJustifyContent(yoga::Justify::Center);
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(150));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(300));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(150));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(300));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -123,8 +123,8 @@ class PointerEventsProcessorTest : public ::testing::Test {
|
||||
auto &props = *sharedProps;
|
||||
listenToAllPointerEvents(props);
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(100));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(100));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
}),
|
||||
@@ -141,8 +141,8 @@ class PointerEventsProcessorTest : public ::testing::Test {
|
||||
yogaStyle.setFlexDirection(yoga::FlexDirection::Column);
|
||||
yogaStyle.setAlignItems(yoga::Align::FlexStart);
|
||||
yogaStyle.setJustifyContent(yoga::Justify::Center);
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(150));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(300));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(150));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(300));
|
||||
return sharedProps;
|
||||
})
|
||||
.children({
|
||||
@@ -155,8 +155,8 @@ class PointerEventsProcessorTest : public ::testing::Test {
|
||||
auto &props = *sharedProps;
|
||||
listenToAllPointerEvents(props);
|
||||
auto &yogaStyle = props.yogaStyle;
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(100));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
|
||||
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(100));
|
||||
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
|
||||
return sharedProps;
|
||||
})
|
||||
})
|
||||
|
||||
@@ -57,62 +57,48 @@ ReactInstance::ReactInstance(
|
||||
timerManager_(std::move(timerManager)),
|
||||
jsErrorHandler_(std::make_shared<JsErrorHandler>(std::move(onJsError))),
|
||||
parentInspectorTarget_(parentInspectorTarget) {
|
||||
RuntimeExecutor runtimeExecutor = [weakRuntime = std::weak_ptr(runtime_),
|
||||
weakTimerManager =
|
||||
std::weak_ptr(timerManager_),
|
||||
weakJsThread =
|
||||
std::weak_ptr(jsMessageQueueThread_),
|
||||
jsErrorHandler =
|
||||
jsErrorHandler_](auto callback) {
|
||||
if (weakRuntime.expired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a fatal error was caught while executing the main bundle, assume the
|
||||
* js runtime is invalid. And stop executing any more js.
|
||||
*/
|
||||
if (!jsErrorHandler->isRuntimeReady() &&
|
||||
jsErrorHandler->hasHandledFatalError()) {
|
||||
LOG(INFO)
|
||||
<< "RuntimeExecutor: Detected fatal error. Dropping work on non-js thread."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto jsThread = weakJsThread.lock()) {
|
||||
jsThread->runOnQueue([jsErrorHandler,
|
||||
weakRuntime,
|
||||
weakTimerManager,
|
||||
callback = std::move(callback)]() {
|
||||
auto runtime = weakRuntime.lock();
|
||||
if (!runtime) {
|
||||
RuntimeExecutor runtimeExecutor =
|
||||
[weakRuntime = std::weak_ptr(runtime_),
|
||||
weakTimerManager = std::weak_ptr(timerManager_),
|
||||
weakJsThread = std::weak_ptr(jsMessageQueueThread_),
|
||||
jsErrorHandler = jsErrorHandler_](auto callback) {
|
||||
if (weakRuntime.expired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
jsi::Runtime& jsiRuntime = runtime->getRuntime();
|
||||
SystraceSection s("ReactInstance::_runtimeExecutor[Callback]");
|
||||
try {
|
||||
ShadowNode::setUseRuntimeShadowNodeReferenceUpdateOnThread(true);
|
||||
callback(jsiRuntime);
|
||||
|
||||
// If we have first-class support for microtasks,
|
||||
// they would've been called as part of the previous callback.
|
||||
if (ReactNativeFeatureFlags::disableEventLoopOnBridgeless()) {
|
||||
if (auto timerManager = weakTimerManager.lock()) {
|
||||
timerManager->callReactNativeMicrotasks(jsiRuntime);
|
||||
if (auto jsThread = weakJsThread.lock()) {
|
||||
jsThread->runOnQueue([jsErrorHandler,
|
||||
weakRuntime,
|
||||
weakTimerManager,
|
||||
callback = std::move(callback)]() {
|
||||
auto runtime = weakRuntime.lock();
|
||||
if (!runtime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (jsi::JSError& originalError) {
|
||||
jsErrorHandler->handleError(jsiRuntime, originalError, true);
|
||||
} catch (std::exception& ex) {
|
||||
jsi::JSError error(
|
||||
jsiRuntime, std::string("Non-js exception: ") + ex.what());
|
||||
jsErrorHandler->handleError(jsiRuntime, error, true);
|
||||
|
||||
jsi::Runtime& jsiRuntime = runtime->getRuntime();
|
||||
SystraceSection s("ReactInstance::_runtimeExecutor[Callback]");
|
||||
try {
|
||||
ShadowNode::setUseRuntimeShadowNodeReferenceUpdateOnThread(true);
|
||||
callback(jsiRuntime);
|
||||
|
||||
// If we have first-class support for microtasks,
|
||||
// they would've been called as part of the previous callback.
|
||||
if (ReactNativeFeatureFlags::disableEventLoopOnBridgeless()) {
|
||||
if (auto timerManager = weakTimerManager.lock()) {
|
||||
timerManager->callReactNativeMicrotasks(jsiRuntime);
|
||||
}
|
||||
}
|
||||
} catch (jsi::JSError& originalError) {
|
||||
jsErrorHandler->handleError(jsiRuntime, originalError, true);
|
||||
} catch (std::exception& ex) {
|
||||
jsi::JSError error(
|
||||
jsiRuntime, std::string("Non-js exception: ") + ex.what());
|
||||
jsErrorHandler->handleError(jsiRuntime, error, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if (parentInspectorTarget_) {
|
||||
auto executor = parentInspectorTarget_->executorFromThis();
|
||||
|
||||
+4
-1
@@ -121,8 +121,11 @@ void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags)
|
||||
[_bridgeModuleDecorator.callableJSModules
|
||||
setBridgelessJSModuleMethodInvoker:^(
|
||||
NSString *moduleName, NSString *methodName, NSArray *args, dispatch_block_t onComplete) {
|
||||
// TODO: Make RCTInstance call onComplete
|
||||
[weakSelf callFunctionOnJSModule:moduleName method:methodName args:args];
|
||||
if (onComplete) {
|
||||
[weakSelf
|
||||
callFunctionOnBufferedRuntimeExecutor:[onComplete](facebook::jsi::Runtime &_) { onComplete(); }];
|
||||
}
|
||||
}];
|
||||
}
|
||||
_launchOptions = launchOptions;
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
|
||||
/** Process ID for all emitted events. */
|
||||
const uint64_t PID = 1000;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool FuseboxTracer::isTracing() {
|
||||
std::lock_guard lock(mutex_);
|
||||
return tracing_;
|
||||
@@ -43,34 +50,43 @@ bool FuseboxTracer::stopTracing(
|
||||
}
|
||||
|
||||
auto traceEvents = folly::dynamic::array();
|
||||
|
||||
// Register "Main" process
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", "Main"))("cat", "__metadata")(
|
||||
"name", "process_name")("ph", "M")("pid", PID)("tid", 0)("ts", 0));
|
||||
// Register "Timings" track
|
||||
// NOTE: This is a hack to make the trace viewer show a "Timings" track
|
||||
// adjacent to custom tracks in our current build of Chrome DevTools.
|
||||
// In future, we should align events exactly.
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", "Timings"))("cat", "__metadata")(
|
||||
"name", "thread_name")("ph", "M")("pid", PID)("tid", 1000)("ts", 0));
|
||||
|
||||
auto savedBuffer = std::move(buffer_);
|
||||
buffer_.clear();
|
||||
|
||||
std::unordered_map<std::string, uint64_t> trackIdMap;
|
||||
uint64_t nextTrack = 1000;
|
||||
|
||||
// Name the main process. Only one process is supported currently.
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", "Main App"))("cat", "__metadata")(
|
||||
"name", "process_name")("ph", "M")("pid", 1000)("tid", 0)("ts", 0));
|
||||
uint64_t nextTrack = 1001;
|
||||
|
||||
for (auto& event : savedBuffer) {
|
||||
if (!trackIdMap.contains(event.track)) {
|
||||
// For events with a custom track name, register track
|
||||
if (event.track.length() && !trackIdMap.contains(event.track)) {
|
||||
auto trackId = nextTrack++;
|
||||
trackIdMap[event.track] = trackId;
|
||||
// New track
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", event.track))(
|
||||
"cat", "__metadata")("name", "thread_name")("ph", "M")("pid", 1000)(
|
||||
"cat", "__metadata")("name", "thread_name")("ph", "M")("pid", PID)(
|
||||
"tid", trackId)("ts", 0));
|
||||
}
|
||||
auto trackId = trackIdMap[event.track];
|
||||
|
||||
// New event
|
||||
auto trackId =
|
||||
trackIdMap.contains(event.track) ? trackIdMap[event.track] : 1000;
|
||||
|
||||
// Emit "blink.user_timing" trace event
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object())("cat", "react.native")(
|
||||
"args", folly::dynamic::object())("cat", "blink.user_timing")(
|
||||
"dur", (event.end - event.start) * 1000)("name", event.name)("ph", "X")(
|
||||
"ts", event.start * 1000)("pid", 1000)("tid", trackId));
|
||||
"ts", event.start * 1000)("pid", PID)("tid", trackId));
|
||||
|
||||
if (traceEvents.size() >= 1000) {
|
||||
resultCallback(traceEvents);
|
||||
@@ -88,13 +104,13 @@ void FuseboxTracer::addEvent(
|
||||
const std::string_view& name,
|
||||
uint64_t start,
|
||||
uint64_t end,
|
||||
const std::string_view& track) {
|
||||
const std::optional<std::string_view>& track) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!tracing_) {
|
||||
return;
|
||||
}
|
||||
buffer_.push_back(
|
||||
BufferEvent{start, end, std::string(name), std::string(track)});
|
||||
buffer_.push_back(BufferEvent{
|
||||
start, end, std::string(name), std::string(track.value_or(""))});
|
||||
}
|
||||
|
||||
bool FuseboxTracer::stopTracingAndWriteToFile(const std::string& path) {
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "folly/dynamic.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
struct BufferEvent {
|
||||
@@ -38,7 +40,7 @@ class FuseboxTracer {
|
||||
const std::string_view& name,
|
||||
uint64_t start,
|
||||
uint64_t end,
|
||||
const std::string_view& track);
|
||||
const std::optional<std::string_view>& track);
|
||||
|
||||
static FuseboxTracer& getFuseboxTracer();
|
||||
|
||||
|
||||
+23
-4
@@ -14,15 +14,33 @@
|
||||
#endif
|
||||
#include <chrono>
|
||||
|
||||
#ifdef WITH_PERFETTO
|
||||
#include "ReactPerfetto.h"
|
||||
#endif
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
#ifdef WITH_PERFETTO
|
||||
namespace {
|
||||
|
||||
const std::string PERFETTO_DEFAULT_TRACK_NAME = "# Web Performance";
|
||||
const std::string PERFETTO_TRACK_NAME_PREFIX = "# Web Performance: ";
|
||||
|
||||
std::string toPerfettoTrackName(
|
||||
const std::optional<std::string_view>& trackName) {
|
||||
return trackName.has_value()
|
||||
? PERFETTO_TRACK_NAME_PREFIX + std::string(trackName.value())
|
||||
: PERFETTO_DEFAULT_TRACK_NAME;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
/* static */ void ReactPerfLogger::measure(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
double endTime,
|
||||
const std::string_view& trackName) {
|
||||
const std::optional<std::string_view>& trackName) {
|
||||
#ifdef HAS_FUSEBOX
|
||||
FuseboxTracer::getFuseboxTracer().addEvent(
|
||||
eventName, (uint64_t)startTime, (uint64_t)endTime, trackName);
|
||||
@@ -30,7 +48,7 @@ namespace facebook::react {
|
||||
|
||||
#ifdef WITH_PERFETTO
|
||||
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
|
||||
auto track = getPerfettoWebPerfTrackAsync(std::string(trackName));
|
||||
auto track = getPerfettoWebPerfTrackAsync(toPerfettoTrackName(trackName));
|
||||
TRACE_EVENT_BEGIN(
|
||||
"react-native",
|
||||
perfetto::DynamicString(eventName.data(), eventName.size()),
|
||||
@@ -45,7 +63,7 @@ namespace facebook::react {
|
||||
/* static */ void ReactPerfLogger::mark(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
const std::string_view& trackName) {
|
||||
const std::optional<std::string_view>& trackName) {
|
||||
// TODO(T203046480) Support mark in FuseboxTracer
|
||||
|
||||
#ifdef WITH_PERFETTO
|
||||
@@ -53,7 +71,7 @@ namespace facebook::react {
|
||||
TRACE_EVENT_INSTANT(
|
||||
"react-native",
|
||||
perfetto::DynamicString(eventName.data(), eventName.size()),
|
||||
getPerfettoWebPerfTrackSync(std::string(trackName)),
|
||||
getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName)),
|
||||
performanceNowToPerfettoTraceTime(startTime));
|
||||
}
|
||||
#endif
|
||||
@@ -62,4 +80,5 @@ namespace facebook::react {
|
||||
/* static */ double ReactPerfLogger::performanceNow() {
|
||||
return chronoToDOMHighResTimeStamp(std::chrono::steady_clock::now());
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+10
-6
@@ -8,26 +8,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <reactperflogger/ReactPerfettoCategories.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* An internal interface for logging performance events to configured React
|
||||
* Native performance tools, such as Perfetto or React Native DevTools.
|
||||
*
|
||||
* Approximates https://w3c.github.io/user-timing/.
|
||||
*/
|
||||
class ReactPerfLogger {
|
||||
public:
|
||||
static void mark(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
const std::string_view& trackName);
|
||||
const std::optional<std::string_view>& trackName);
|
||||
|
||||
/**
|
||||
* This accepts performance events that should go to internal tracing
|
||||
* frameworks like Perfetto, and should go to DevTools like Fusebox.
|
||||
*/
|
||||
static void measure(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
double endTime,
|
||||
const std::string_view& trackName);
|
||||
const std::optional<std::string_view>& trackName);
|
||||
|
||||
static double performanceNow();
|
||||
};
|
||||
|
||||
@@ -245,6 +245,12 @@ const char* YGUnitToString(const YGUnit value) {
|
||||
return "percent";
|
||||
case YGUnitAuto:
|
||||
return "auto";
|
||||
case YGUnitMaxContent:
|
||||
return "max-content";
|
||||
case YGUnitFitContent:
|
||||
return "fit-content";
|
||||
case YGUnitStretch:
|
||||
return "stretch";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -131,7 +131,10 @@ YG_ENUM_DECL(
|
||||
YGUnitUndefined,
|
||||
YGUnitPoint,
|
||||
YGUnitPercent,
|
||||
YGUnitAuto)
|
||||
YGUnitAuto,
|
||||
YGUnitMaxContent,
|
||||
YGUnitFitContent,
|
||||
YGUnitStretch)
|
||||
|
||||
YG_ENUM_DECL(
|
||||
YGWrap,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user