diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 1ab45de9789..8d3aec5dc6b 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -83,7 +83,7 @@ export type EventTypeShape = $ReadOnly<{| optional: boolean, typeAnnotation: $ReadOnly<{| type: 'EventTypeAnnotation', - argument: $ReadOnly<{| + argument?: $ReadOnly<{| type: 'ObjectTypeAnnotation', properties: $ReadOnlyArray, |}>, diff --git a/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js b/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js index ccd3a1f0c52..c6820ddc502 100644 --- a/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js +++ b/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js @@ -55,6 +55,12 @@ void ::_CLASSNAME_::EventEmitter::::_EVENT_NAME_::(::_STRUCT_NAME_:: event) cons } `.trim(); +const basicComponentTemplate = ` +void ::_CLASSNAME_::EventEmitter::::_EVENT_NAME_::() const { + dispatchEvent("::_DISPATCH_EVENT_NAME_::"); +} +`.trim(); + function generateSetter(variableName, propertyName, propertyParts) { const trailingPeriod = propertyParts.length === 0 ? '' : '.'; const eventChain = `event.${propertyParts.join( @@ -106,16 +112,6 @@ function generateSetters( } function generateEvent(componentName: string, event): string { - const implementation = ` - auto payload = jsi::Object(runtime); - ${generateSetters('payload', event.typeAnnotation.argument.properties, [])} - return payload; - `.trim(); - - if (!event.name.startsWith('on')) { - throw new Error('Expected the event name to start with `on`'); - } - // This is a gross hack necessary because native code is sending // events named things like topChange to JS which is then converted back to // call the onChange prop. We should be consistent throughout the system. @@ -126,15 +122,32 @@ function generateEvent(componentName: string, event): string { 3, )}`; - return componentTemplate + if (event.typeAnnotation.argument) { + const implementation = ` + auto payload = jsi::Object(runtime); + ${generateSetters('payload', event.typeAnnotation.argument.properties, [])} + return payload; + `.trim(); + + if (!event.name.startsWith('on')) { + throw new Error('Expected the event name to start with `on`'); + } + + return componentTemplate + .replace(/::_CLASSNAME_::/g, componentName) + .replace(/::_EVENT_NAME_::/g, event.name) + .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName) + .replace( + '::_STRUCT_NAME_::', + generateStructName(componentName, [event.name]), + ) + .replace('::_IMPLEMENTATION_::', implementation); + } + + return basicComponentTemplate .replace(/::_CLASSNAME_::/g, componentName) .replace(/::_EVENT_NAME_::/g, event.name) - .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName) - .replace( - '::_STRUCT_NAME_::', - generateStructName(componentName, [event.name]), - ) - .replace('::_IMPLEMENTATION_::', implementation); + .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName); } module.exports = { diff --git a/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js b/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js index 2b4909837a9..075f124c25e 100644 --- a/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js +++ b/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js @@ -146,21 +146,27 @@ function generateStructs(componentName: string, component): string { const structs: StructsMap = new Map(); component.events.forEach(event => { - generateStruct( - structs, - componentName, - [event.name], - event.typeAnnotation.argument.properties, - ); + if (event.typeAnnotation.argument) { + generateStruct( + structs, + componentName, + [event.name], + event.typeAnnotation.argument.properties, + ); + } }); return Array.from(structs.values()).join('\n\n'); } function generateEvent(componentName: string, event: EventTypeShape): string { - const structName = generateStructName(componentName, [event.name]); + if (event.typeAnnotation.argument) { + const structName = generateStructName(componentName, [event.name]); - return `void ${event.name}(${structName} value) const;`; + return `void ${event.name}(${structName} value) const;`; + } + + return `void ${event.name}() const;`; } function generateEvents(componentName: string, component): string { return component.events diff --git a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js index 4bb696833cf..8e95a41bede 100644 --- a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js @@ -560,6 +560,14 @@ const EVENT_PROPS: SchemaType = { }, }, }, + { + name: 'onEnd', + optional: true, + bubblingType: 'bubble', + typeAnnotation: { + type: 'EventTypeAnnotation', + }, + }, ], props: [ { diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap index 41ed47758c4..25846b02b5d 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap @@ -165,6 +165,9 @@ void EventsNativeComponentEventEmitter::onEventDirect(EventsNativeComponentOnEve return payload; }); } +void EventsNativeComponentEventEmitter::onEnd() const { + dispatchEvent(\\"end\\"); +} } // namespace react } // namespace facebook diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap index bf3c4da2b95..bff692ada26 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap @@ -173,6 +173,8 @@ class EventsNativeComponentEventEmitter : public ViewEventEmitter { void onChange(EventsNativeComponentOnChangeStruct value) const; void onEventDirect(EventsNativeComponentOnEventDirectStruct value) const; + + void onEnd() const; }; } // namespace react diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 86933768e59..8e7ec6e5fb5 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -285,6 +285,13 @@ const EventsNativeComponentViewConfig = { bubbled: 'onChange', }, }, + + topEnd: { + phasedRegistrationNames: { + captured: 'onEndCapture', + bubbled: 'onEnd', + }, + }, }, directEventTypes: { @@ -300,6 +307,7 @@ const EventsNativeComponentViewConfig = { disabled: true, onChange: true, onEventDirect: true, + onEnd: true, }, };