Skip to content

Commit da5e00c

Browse files
Merge remote-tracking branch 'origin/master' into react-18-2-0
2 parents 2119beb + b1e09e0 commit da5e00c

29 files changed

+479
-751
lines changed

.github/workflows/dart_ci.yml

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,46 @@ on:
1010
- '**'
1111

1212
jobs:
13+
# Run as a separate job outside the Dart SDK matrix below,
14+
# since we can only emit a single SBOM.
15+
create-sbom-release-asset:
16+
name: Create SBOM Release Asset
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: dart-lang/setup-dart@v1
21+
with:
22+
sdk: 2.19.6 # This version doesn't matter so long as it resolves.
23+
- run: dart pub get
24+
- name: Publish SBOM to Release Assets
25+
uses: anchore/sbom-action@v0
26+
with:
27+
path: ./
28+
format: cyclonedx-json
29+
1330
build:
1431
runs-on: ubuntu-latest
1532
strategy:
1633
fail-fast: false
1734
matrix:
18-
# Can't run on `stable` (Dart 3) until we're fully null-safe.
19-
sdk: [2.18.7, 2.19.6]
35+
sdk: [2.19.6, stable]
2036
steps:
2137
- uses: actions/checkout@v2
22-
- uses: dart-lang/setup-dart@v1
38+
- id: setup-dart
39+
uses: dart-lang/setup-dart@v1
2340
with:
2441
sdk: ${{ matrix.sdk }}
2542

2643
- name: Print Dart SDK version
2744
run: dart --version
2845

46+
- name: Delete Dart-2-only files when running on Dart 3
47+
run: |
48+
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
49+
if [[ "$DART_VERSION" =~ ^3 ]]; then
50+
./tool/delete_dart_2_only_files.sh
51+
fi
52+
2953
- id: install
3054
name: Install dependencies
3155
run: dart pub get
@@ -36,28 +60,20 @@ jobs:
3660

3761
- name: Verify formatting
3862
run: dart run dart_dev format --check
39-
if: ${{ matrix.sdk == '2.18.7' }}
63+
if: ${{ matrix.sdk == '2.19.6' }}
4064

4165
- name: Analyze project source
4266
run: dart analyze
4367
if: always() && steps.install.outcome == 'success'
4468

4569
- name: Run tests (DDC)
4670
run: |
47-
if [ ${{ matrix.sdk }} = '2.13.4' ]; then
48-
dart run build_runner test --delete-conflicting-outputs -- --preset dartdevc-legacy
49-
else
50-
dart run build_runner test --delete-conflicting-outputs -- --preset dartdevc
51-
fi
71+
dart run build_runner test --delete-conflicting-outputs -- --preset dartdevc
5272
if: always() && steps.install.outcome == 'success'
53-
timeout-minutes: 5
73+
timeout-minutes: 8
5474

5575
- name: Run tests (dart2js)
5676
run: |
57-
if [ ${{ matrix.sdk }} = '2.13.4' ]; then
58-
dart run build_runner test --delete-conflicting-outputs --release -- --preset dart2js-legacy
59-
else
60-
dart run build_runner test --delete-conflicting-outputs --release -- --preset dart2js
61-
fi
77+
dart run build_runner test --delete-conflicting-outputs --release -- --preset dart2js
6278
if: always() && steps.install.outcome == 'success'
63-
timeout-minutes: 5
79+
timeout-minutes: 8

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## 7.2.0
2+
- Add Dart wrapper for React [lazy](https://react.dev/reference/react/lazy)
3+
4+
## 7.1.3
5+
- Internal release tooling changes
6+
7+
## 7.1.2
8+
- Internal release tooling changes
9+
10+
## 7.1.1
11+
- Internal release tooling changes
12+
- Tests - switch from mockito to mocktail
13+
14+
## 7.1.0
15+
16+
Add a new `ReactNode` type, which aliases `Object?` to mimic [the React JS Typescript type](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts#L214).
17+
118
## 7.0.1
219

320
Breaking change - fix nullability/typings for `ReactDom.findDomNode` and `ReactDom.render` from `package:react/react_client/react_interop.dart`:

Dockerfile

Lines changed: 0 additions & 14 deletions
This file was deleted.

dart_test.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ platforms:
44
- chrome
55
- vm
66

7+
# Work around process handing after tests finish: https://github.com/dart-lang/build/issues/3765
8+
concurrency: 1
9+
710
presets:
811
dart2js-legacy:
912
exclude_tags: no-dart2js

example/suspense/suspense.dart

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,39 @@
11
@JS()
2-
library js_components;
2+
library example.suspense.suspense;
33

44
import 'dart:html';
5-
import 'dart:js_util';
65

76
import 'package:js/js.dart';
7+
import 'package:react/hooks.dart';
88
import 'package:react/react.dart' as react;
9-
import 'package:react/react_client.dart';
10-
import 'package:react/react_client/react_interop.dart';
119
import 'package:react/react_dom.dart' as react_dom;
12-
import 'package:react/src/js_interop_util.dart';
1310
import './simple_component.dart' deferred as simple;
1411

15-
@JS('React.lazy')
16-
external ReactClass jsLazy(Promise Function() factory);
17-
18-
// Only intended for testing purposes, Please do not copy/paste this into repo.
19-
// This will most likely be added to the PUBLIC api in the future,
20-
// but needs more testing and Typing decisions to be made first.
21-
ReactJsComponentFactoryProxy lazy(Future<ReactComponentFactoryProxy> Function() factory) =>
22-
ReactJsComponentFactoryProxy(
23-
jsLazy(
24-
allowInterop(
25-
() => futureToPromise(
26-
// React.lazy only supports "default exports" from a module.
27-
// This `{default: yourExport}` workaround can be found in the React.lazy RFC comments.
28-
// See: https://github.com/reactjs/rfcs/pull/64#issuecomment-431507924
29-
(() async => jsify({'default': (await factory()).type}))(),
30-
),
31-
),
32-
),
33-
);
34-
3512
main() {
3613
final content = wrapper({});
3714

3815
react_dom.render(content, querySelector('#content')!);
3916
}
4017

41-
final lazyComponent = lazy(() async {
42-
await simple.loadLibrary();
18+
final lazyComponent = react.lazy(() async {
4319
await Future.delayed(Duration(seconds: 5));
20+
await simple.loadLibrary();
21+
4422
return simple.SimpleComponent;
4523
});
4624

4725
var wrapper = react.registerFunctionComponent(WrapperComponent, displayName: 'wrapper');
4826

4927
WrapperComponent(Map props) {
28+
final showComponent = useState(false);
5029
return react.div({
5130
'id': 'lazy-wrapper'
5231
}, [
53-
react.Suspense({'fallback': 'Loading...'}, [lazyComponent({})])
32+
react.button({
33+
'onClick': (_) {
34+
showComponent.set(!showComponent.value);
35+
}
36+
}, 'Toggle component'),
37+
react.Suspense({'fallback': 'Loading...'}, showComponent.value ? lazyComponent({}) : null)
5438
]);
5539
}

example/test/react_test_components.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ class _ClockComponent extends react.Component {
129129

130130
@override
131131
render() {
132-
return react.span({'onClick': (event) => print('Hello World!')},
132+
return react.span(
133+
{'onClick': (event) => print('Hello World!')},
133134
// { 'onClick': (event, [domid = null]) => print("Hello World!") },
134135
['Seconds elapsed: ', "${state['secondsElapsed']}"]);
135136
}

lib/react.dart

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ export 'package:react/src/context.dart';
2222
export 'package:react/src/prop_validator.dart';
2323
export 'package:react/src/react_client/event_helpers.dart';
2424
export 'package:react/react_client/react_interop.dart' show forwardRef2, createRef, memo2;
25+
export 'package:react/src/react_client/lazy.dart' show lazy;
2526
export 'package:react/src/react_client/synthetic_event_wrappers.dart' hide NonNativeDataTransfer;
2627
export 'package:react/src/react_client/synthetic_data_transfer.dart' show SyntheticDataTransfer;
27-
export 'package:react/src/react_client/event_helpers.dart';
2828

2929
/// A React component declared using a function that takes in [props] and returns rendered output.
3030
///
3131
/// See <https://reactjs.org/docs/components-and-props.html#function-and-class-components>.
3232
///
3333
/// [props] is typed as [JsBackedMap] so that dart2js can optimize props accesses.
34-
typedef DartFunctionComponent = dynamic Function(JsBackedMap props);
34+
typedef DartFunctionComponent = /*ReactNode*/ dynamic Function(JsBackedMap props);
3535

3636
/// The callback to a React forwardRef component. See [forwardRef2] for more details.
3737
///
@@ -40,7 +40,7 @@ typedef DartFunctionComponent = dynamic Function(JsBackedMap props);
4040
/// In the current JS implementation, the ref argument to [React.forwardRef] is usually a JsRef object no matter the input ref type,
4141
/// but according to React the ref argument can be any ref type: https://github.com/facebook/flow/blob/master@%7B2020-09-08%7D/lib/react.js#L305
4242
/// and not just a ref object, so we type [ref] as dynamic here.
43-
typedef DartForwardRefFunctionComponent = dynamic Function(JsBackedMap props, dynamic ref);
43+
typedef DartForwardRefFunctionComponent = /*ReactNode*/ dynamic Function(JsBackedMap props, dynamic ref);
4444

4545
typedef ComponentFactory<T extends Component> = T Function();
4646

@@ -543,12 +543,10 @@ abstract class Component {
543543

544544
/// __Required.__
545545
///
546-
/// When called, it should examine [props] and [state] and return a single child `Element`. This child `Element` can
547-
/// be either a virtual representation of a native DOM component (such as `DivElement`) or another composite
548-
/// `Component` that you've defined yourself.
546+
/// When called, it should examine [props] and [state] and return a [ReactNode].
549547
///
550-
/// See: <https://reactjs.org/docs/react-component.html#render>
551-
dynamic render();
548+
/// See: <https://legacy.reactjs.org/docs/react-component.html#render>
549+
/*ReactNode*/ dynamic render();
552550
}
553551

554552
/// Top-level ReactJS [Component class](https://reactjs.org/docs/react-component.html)
@@ -933,13 +931,7 @@ abstract class Component2 implements Component {
933931
/// See: <https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes>
934932
Map<String, PropValidator<Never>> get propTypes => {};
935933

936-
/// Examines [props] and [state] and returns one of the following types:
937-
///
938-
/// * [ReactElement] (renders a single DOM `Element`)
939-
/// * [Fragment] (renders multiple elements)
940-
/// * [ReactPortal] (renders children into a different DOM subtree)
941-
/// * `String` / `num` (renders text nodes in the DOM)
942-
/// * `bool` / `null` (renders nothing)
934+
/// Examines [props] and [state] and returns a [ReactNode].
943935
///
944936
/// This method is __required__ for class components.
945937
///
@@ -950,9 +942,9 @@ abstract class Component2 implements Component {
950942
/// If you need to interact with the browser / DOM apis, perform your work in [componentDidMount]
951943
/// or the other lifecycle methods instead. Keeping `render` pure makes components easier to think about.
952944
///
953-
/// See: <https://reactjs.org/docs/react-component.html#render>
945+
/// See: <https://legacy.reactjs.org/docs/react-component.html#render>
954946
@override
955-
dynamic render();
947+
/*ReactNode*/ dynamic render();
956948

957949
// ******************************************************************************************************************
958950
//

lib/react_client.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export 'package:react/react_client/component_factory.dart'
2020
JsBackedMapComponentFactoryMixin;
2121
export 'package:react/react_client/zone.dart' show componentZone;
2222
export 'package:react/src/react_client/chain_refs.dart' show chainRefs, chainRefList;
23-
export 'package:react/src/typedefs.dart' show JsFunctionComponent;
23+
export 'package:react/src/typedefs.dart' show JsFunctionComponent, ReactNode;
2424

2525
/// Method used to initialize the React environment.
2626
///

lib/react_client/component_factory.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export 'package:react/src/react_client/factory_util.dart' show generateJsProps;
2222
/// Currently only involves converting a top-level non-[List] [Iterable] to
2323
/// a non-growable [List], but this may be updated in the future to support
2424
/// advanced nesting and other kinds of children.
25-
dynamic listifyChildren(dynamic children) {
25+
ReactNode listifyChildren(ReactNode children) {
2626
if (React.isValidElement(children)) {
2727
// Short-circuit if we're dealing with a ReactElement to avoid the dart2js
2828
// interceptor lookup involved in Dart type-checking.
@@ -63,7 +63,7 @@ Map unconvertJsProps(/* ReactElement|ReactComponent */ instance) {
6363
/// Shared component factory proxy [build] method for components that utilize [JsBackedMap]s.
6464
mixin JsBackedMapComponentFactoryMixin on ReactComponentFactoryProxy {
6565
@override
66-
ReactElement build(Map props, [List childrenArgs = const []]) {
66+
ReactElement build(Map props, [List<ReactNode> childrenArgs = const []]) {
6767
final children = generateChildren(childrenArgs, shouldAlwaysBeList: true);
6868
final convertedProps = generateExtendedJsProps(props);
6969
return React.createElement(type, convertedProps, children);
@@ -89,7 +89,7 @@ class ReactDartComponentFactoryProxy<TComponent extends Component> extends React
8989
ReactClass get type => reactClass;
9090

9191
@override
92-
ReactElement build(Map props, [List childrenArgs = const []]) {
92+
ReactElement build(Map props, [List<ReactNode> childrenArgs = const []]) {
9393
var children = convertArgsToChildren(childrenArgs);
9494
children = listifyChildren(children);
9595

@@ -98,7 +98,7 @@ class ReactDartComponentFactoryProxy<TComponent extends Component> extends React
9898

9999
/// Returns a JavaScript version of the specified [props], preprocessed for consumption by ReactJS and prepared for
100100
/// consumption by the `react` library internals.
101-
static InteropProps generateExtendedJsProps(Map props, dynamic children, {Map? defaultProps}) {
101+
static InteropProps generateExtendedJsProps(Map props, ReactNode children, {Map? defaultProps}) {
102102
if (children == null) {
103103
children = [];
104104
} else if (children is! Iterable) {
@@ -212,8 +212,8 @@ class ReactJsContextComponentFactoryProxy extends ReactJsComponentFactoryProxy {
212212
super(jsClass, shouldConvertDomProps: shouldConvertDomProps);
213213

214214
@override
215-
ReactElement build(Map props, [List childrenArgs = const []]) {
216-
dynamic children = generateChildren(childrenArgs);
215+
ReactElement build(Map props, [List<ReactNode> childrenArgs = const []]) {
216+
var children = generateChildren(childrenArgs);
217217

218218
if (isConsumer) {
219219
if (children is Function) {
@@ -271,7 +271,7 @@ class ReactJsComponentFactoryProxy extends ReactComponentFactoryProxy {
271271
}
272272

273273
@override
274-
ReactElement build(Map props, [List childrenArgs = const []]) {
274+
ReactElement build(Map props, [List<ReactNode> childrenArgs = const []]) {
275275
final children = generateChildren(childrenArgs, shouldAlwaysBeList: alwaysReturnChildrenAsList);
276276
final convertedProps =
277277
generateJsProps(props, convertCallbackRefValue: false, additionalRefPropKeys: _additionalRefPropKeys);
@@ -292,7 +292,7 @@ class ReactDomComponentFactoryProxy extends ReactComponentFactoryProxy {
292292
String get type => name;
293293

294294
@override
295-
ReactElement build(Map props, [List childrenArgs = const []]) {
295+
ReactElement build(Map props, [List<ReactNode> childrenArgs = const []]) {
296296
final children = generateChildren(childrenArgs);
297297
final convertedProps = generateJsProps(props, convertCallbackRefValue: false, wrapWithJsify: true);
298298
return React.createElement(type, convertedProps, children);

0 commit comments

Comments
 (0)