diff --git a/lib/src/react_client/event_helpers.dart b/lib/src/react_client/event_helpers.dart index d7c2d5ff..69efc8fd 100644 --- a/lib/src/react_client/event_helpers.dart +++ b/lib/src/react_client/event_helpers.dart @@ -4,6 +4,7 @@ library react_client.event_helpers; import 'dart:html'; import 'package:js/js_util.dart'; +import 'package:meta/meta.dart'; import 'package:react/react_client/js_interop_helpers.dart'; import 'package:react/src/react_client/synthetic_data_transfer.dart'; import 'package:react/src/react_client/synthetic_event_wrappers.dart'; @@ -72,7 +73,7 @@ SyntheticMouseEvent wrapNativeMouseEvent(MouseEvent nativeEvent) { 'clientX': nativeEvent.client.x, 'clientY': nativeEvent.client.y, 'ctrlKey': nativeEvent.ctrlKey, - 'dataTransfer': nativeEvent.dataTransfer, + 'dataTransfer': nativeEvent.safeDataTransfer, 'metaKey': nativeEvent.metaKey, 'pageX': nativeEvent.page.x, 'pageY': nativeEvent.page.y, @@ -823,3 +824,28 @@ extension DataTransferHelper on SyntheticMouseEvent { /// See SyntheticDataTransfer? get dataTransfer => syntheticDataTransferFactory(getProperty(this, 'dataTransfer')); } + +extension SafeNativeDataTransfer on MouseEvent { + /// In Dart SDK versions with null-safety enabled, + /// [the interop](https://github.com/dart-lang/sdk/blob/master/sdk/lib/html/dart2js/html_dart2js.dart#L22421-L22422) + /// for [MouseEvent.dataTransfer] is non-nullable despite the + /// [JS spec for `dataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/dataTransfer) + /// clearly indicating that it can be null. + /// + /// This can cause the SDK to throw when a `MouseEvent` is manually constructed, and the `dataTransfer` + /// getter is then accessed when running with `sound_null_safety` enabled: + /// ``` + /// Unexpected null value encountered in Dart web platform libraries. + /// ``` + /// + /// This extension is used to catch the error within our [wrapNativeMouseEvent] function so that + /// `SyntheticMouseEvent`s do not throw the null exception. + @internal + DataTransfer? get safeDataTransfer { + DataTransfer? dataTransfer; + try { + dataTransfer = this.dataTransfer; + } catch (_) {} + return dataTransfer; + } +} diff --git a/test/react_client/event_helpers_test.dart b/test/react_client/event_helpers_test.dart index 4613e5d0..06eaf910 100644 --- a/test/react_client/event_helpers_test.dart +++ b/test/react_client/event_helpers_test.dart @@ -2105,6 +2105,15 @@ main() { }); }); }); + + // See: `SafeNativeDataTransfer` extension + group('SafeNativeDataTransfer MouseEvent extension', () { + test( + 'prevents faulty Dart SDK web platform null exceptions when ' + 'accessing the `dataTransfer` getter on a manually constructed MouseEvent', () { + expect(() => wrapNativeMouseEvent(MouseEvent('click')).dataTransfer, returnsNormally); + }); + }); } enum SyntheticEventType {