diff --git a/packages/react-native-codegen/buck_tests/java/BooleanPropNativeComponentViewManager.java b/packages/react-native-codegen/buck_tests/java/BooleanPropNativeComponentViewManager.java index 40292c89a09..52d10812c1a 100644 --- a/packages/react-native-codegen/buck_tests/java/BooleanPropNativeComponentViewManager.java +++ b/packages/react-native-codegen/buck_tests/java/BooleanPropNativeComponentViewManager.java @@ -1,6 +1,7 @@ package com.facebook.react.uimanager; import android.view.ViewGroup; +import androidx.annotation.Nullable; import com.facebook.react.viewmanagers.BooleanPropNativeComponentViewManagerDelegate; import com.facebook.react.viewmanagers.BooleanPropNativeComponentViewManagerInterface; @@ -26,4 +27,7 @@ public class BooleanPropNativeComponentViewManager extends SimpleViewManager, + disabledNullable?: WithDefault, |}>; export default (codegenNativeComponent( diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index ef63da62f1b..b6f2d355cfb 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -91,7 +91,7 @@ export type ObjectPropertyType = type PropTypeTypeAnnotation = | $ReadOnly<{| type: 'BooleanTypeAnnotation', - default: boolean, + default: boolean | null, |}> | $ReadOnly<{| type: 'StringTypeAnnotation', diff --git a/packages/react-native-codegen/src/generators/components/CppHelpers.js b/packages/react-native-codegen/src/generators/components/CppHelpers.js index 69a1d9a61ee..825d351fa90 100644 --- a/packages/react-native-codegen/src/generators/components/CppHelpers.js +++ b/packages/react-native-codegen/src/generators/components/CppHelpers.js @@ -120,6 +120,9 @@ function convertDefaultTypeToString( const typeAnnotation = prop.typeAnnotation; switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': + if (typeAnnotation.default == null) { + return ''; + } return String(typeAnnotation.default); case 'StringTypeAnnotation': if (typeAnnotation.default == null) { diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js index 0470a5fac25..c7007f2f462 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js @@ -70,7 +70,11 @@ function getJavaValueForProp( switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': - return `value == null ? ${typeAnnotation.default.toString()} : (boolean) value`; + if (typeAnnotation.default === null) { + return 'value == null ? null : (Boolean) value'; + } else { + return `value == null ? ${typeAnnotation.default.toString()} : (boolean) value`; + } case 'StringTypeAnnotation': const defaultValueString = typeAnnotation.default === null diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js index 228cfe01ad7..632d7756fef 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js @@ -52,7 +52,12 @@ function getJavaValueForProp(prop: PropTypeShape, imports): string { switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': - return 'boolean value'; + if (typeAnnotation.default === null) { + addNullable(imports); + return '@Nullable Boolean value'; + } else { + return 'boolean value'; + } case 'StringTypeAnnotation': addNullable(imports); return '@Nullable String value'; diff --git a/packages/react-native-codegen/src/generators/components/GenerateTests.js b/packages/react-native-codegen/src/generators/components/GenerateTests.js index 0aeb92ab703..07c140745c3 100644 --- a/packages/react-native-codegen/src/generators/components/GenerateTests.js +++ b/packages/react-native-codegen/src/generators/components/GenerateTests.js @@ -71,7 +71,7 @@ function getTestCasesForProp(propName, typeAnnotation) { } else if (typeAnnotation.type === 'BooleanTypeAnnotation') { cases.push({ propName: propName, - propValue: typeAnnotation.default || true, + propValue: typeAnnotation.default != null ? typeAnnotation.default : true, }); } else if (typeAnnotation.type === 'IntegerTypeAnnotation') { cases.push({ diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap index 4ba7c8cdd5e..13145efd27b 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap @@ -87,7 +87,7 @@ TEST(BooleanPropNativeComponentProps_disabled, etc) { auto propParser = RawPropsParser(); propParser.prepare(); auto const &sourceProps = BooleanPropNativeComponentProps(); - auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", true)); + auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", false)); rawProps.parse(propParser); BooleanPropNativeComponentProps(sourceProps, rawProps); }", @@ -254,7 +254,7 @@ TEST(EventsNestedObjectNativeComponentProps_disabled, etc) { auto propParser = RawPropsParser(); propParser.prepare(); auto const &sourceProps = EventsNestedObjectNativeComponentProps(); - auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", true)); + auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", false)); rawProps.parse(propParser); EventsNestedObjectNativeComponentProps(sourceProps, rawProps); }", @@ -291,7 +291,7 @@ TEST(EventsNativeComponentProps_disabled, etc) { auto propParser = RawPropsParser(); propParser.prepare(); auto const &sourceProps = EventsNativeComponentProps(); - auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", true)); + auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", false)); rawProps.parse(propParser); EventsNativeComponentProps(sourceProps, rawProps); }", @@ -829,7 +829,7 @@ TEST(MultiFile1NativeComponentProps_disabled, etc) { auto propParser = RawPropsParser(); propParser.prepare(); auto const &sourceProps = MultiFile1NativeComponentProps(); - auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", true)); + auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", false)); rawProps.parse(propParser); MultiFile1NativeComponentProps(sourceProps, rawProps); } @@ -884,7 +884,7 @@ TEST(MultiComponent1NativeComponentProps_disabled, etc) { auto propParser = RawPropsParser(); propParser.prepare(); auto const &sourceProps = MultiComponent1NativeComponentProps(); - auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", true)); + auto const &rawProps = RawProps(folly::dynamic::object(\\"disabled\\", false)); rawProps.parse(propParser); MultiComponent1NativeComponentProps(sourceProps, rawProps); } diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js index af505f97bac..2fffe662bd4 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js @@ -205,6 +205,10 @@ type ModuleProps = $ReadOnly<{| boolean_optional_key?: WithDefault, boolean_optional_both?: WithDefault, + // Boolean props, null default + boolean_null_optional_key?: WithDefault, + boolean_null_optional_both?: WithDefault, + // String props string_required: string, string_optional_key?: WithDefault, diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index 5ca530df4e0..bd8d1af326f 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -73,6 +73,22 @@ Object { "type": "BooleanTypeAnnotation", }, }, + Object { + "name": "boolean_null_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "BooleanTypeAnnotation", + }, + }, + Object { + "name": "boolean_null_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "BooleanTypeAnnotation", + }, + }, Object { "name": "string_required", "optional": false, diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index 25cf5b161b7..7a0c1bf64bb 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -161,7 +161,13 @@ function getTypeAnnotationForArray(name, typeAnnotation, defaultValue, types) { } } -function getTypeAnnotation(name, annotation, defaultValue, types) { +function getTypeAnnotation( + name, + annotation, + defaultValue, + withNullDefault, + types, +) { const typeAnnotation = getValueFromTypes(annotation, types); if ( @@ -241,7 +247,9 @@ function getTypeAnnotation(name, annotation, defaultValue, types) { case 'BooleanTypeAnnotation': return { type: 'BooleanTypeAnnotation', - default: ((defaultValue == null ? false : defaultValue): boolean), + default: withNullDefault + ? (defaultValue: boolean | null) + : ((defaultValue == null ? false : defaultValue): boolean), }; case 'StringTypeAnnotation': if (typeof defaultValue !== 'undefined') { @@ -349,6 +357,7 @@ function buildPropSchema(property, types: TypeMap): ?PropTypeShape { } let defaultValue = null; + let withNullDefault = false; if ( type === 'GenericTypeAnnotation' && typeAnnotation.id.name === 'WithDefault' @@ -369,13 +378,18 @@ function buildPropSchema(property, types: TypeMap): ?PropTypeShape { : typeAnnotation.type; if (defaultValueType === 'NullLiteralTypeAnnotation') { - if (type !== 'StringTypeAnnotation' && type !== 'Stringish') { + if ( + type !== 'StringTypeAnnotation' && + type !== 'Stringish' && + type !== 'BooleanTypeAnnotation' + ) { throw new Error( - `WithDefault can only provide a 'null' default value for string types (see ${name})`, + `WithDefault can only provide a 'null' default value for string and boolean types (see ${name})`, ); } defaultValue = null; + withNullDefault = true; } } @@ -386,6 +400,7 @@ function buildPropSchema(property, types: TypeMap): ?PropTypeShape { name, typeAnnotation, defaultValue, + withNullDefault, types, ), };