@@ -19,6 +19,8 @@ import 'package:react/react_client.dart' show ComponentFactory;
19
19
import 'package:react/react_client/bridge.dart' ;
20
20
import 'package:react/react_client/js_backed_map.dart' ;
21
21
import 'package:react/react_client/component_factory.dart' show ReactJsComponentFactoryProxy;
22
+ import 'package:react/react_client/js_interop_helpers.dart' ;
23
+ import 'package:react/react_client/private_utils.dart' ;
22
24
import 'package:react/src/react_client/dart2_interop_workaround_bindings.dart' ;
23
25
24
26
typedef ReactElement ReactJsComponentFactory (props, children);
@@ -32,6 +34,7 @@ typedef dynamic JsPropValidator(
32
34
@JS ()
33
35
abstract class React {
34
36
external static String get version;
37
+ external static ReactElement cloneElement (ReactElement element, [JsMap props, dynamic children]);
35
38
external static ReactContext createContext ([
36
39
dynamic defaultValue,
37
40
int Function (dynamic currentValue, dynamic nextValue) calculateChangedBits,
@@ -132,15 +135,107 @@ class JsRef {
132
135
133
136
/// Automatically passes a [Ref] through a component to one of its children.
134
137
///
138
+ /// __Example 1:__ Forwarding refs to DOM components
139
+ ///
140
+ /// _[Analogous JS Demo] (https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components)_
141
+ ///
142
+ /// ```dart
143
+ /// import 'dart:html';
144
+ /// import 'package:react/react.dart' as react;
145
+ ///
146
+ /// // ---------- Component Definition ----------
147
+ /// final FancyButton = react.forwardRef((props, ref) {
148
+ /// return react.button({'ref': ref, 'className': 'FancyButton'}, 'Click me!');
149
+ /// }, displayName: 'FancyButton');
150
+ ///
151
+ /// // ---------- Component Consumption ----------
152
+ /// void main() {
153
+ /// final ref = createRef<Element>();
154
+ ///
155
+ /// react_dom.render(FancyButton({'ref': ref}));
156
+ ///
157
+ /// // You can now get a ref directly to the DOM button:
158
+ /// final buttonNode = ref.current;
159
+ /// }
160
+ /// ```
161
+ ///
162
+ /// __Example 2:__ Forwarding refs in higher-order components
163
+ ///
164
+ /// _[Analogous JS Demo] (https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-in-higher-order-components)_
165
+ ///
166
+ /// ```dart
167
+ /// import 'dart:html';
168
+ /// import 'package:react/react.dart' as react;
169
+ /// import 'package:react/react_client.dart' show setClientConfiguration, ReactJsComponentFactoryProxy;
170
+ /// import 'package:react/react_dom.dart' as react_dom;
171
+ ///
172
+ /// // ---------- Component Definitions ----------
173
+ ///
174
+ /// final FancyButton = react.forwardRef((props, ref) {
175
+ /// return react.button({'ref': ref, 'className': 'FancyButton'}, 'Click me!');
176
+ /// }, displayName: 'FancyButton');
177
+ ///
178
+ /// class _LogProps extends react.Component2 {
179
+ /// @override
180
+ /// void componentDidUpdate(Map prevProps, _, [__]) {
181
+ /// print('old props: $prevProps');
182
+ /// print('new props: ${this.props}');
183
+ /// }
184
+ ///
185
+ /// @override
186
+ /// render() {
187
+ /// final propsToForward = {...props}..remove('forwardedRef');
188
+ ///
189
+ /// // Assign the custom prop `forwardedRef` as a ref on the component passed in via `props.component`
190
+ /// return props['component']({...propsToForward, 'ref': props['forwardedRef']}, props['children']);
191
+ /// }
192
+ /// }
193
+ /// final _logPropsHoc = react.registerComponent2(() => _LogProps());
194
+ ///
195
+ /// final LogProps = react.forwardRef((props, ref) {
196
+ /// // Note the second param "ref" provided by react.forwardRef.
197
+ /// // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
198
+ /// // And it can then be attached to the Component.
199
+ /// return _logPropsHoc({...props, 'forwardedRef': ref});
200
+ /// // Optional: Make the displayName more useful for the React dev tools.
201
+ /// // See: https://reactjs.org/docs/forwarding-refs.html#displaying-a-custom-name-in-devtools
202
+ /// }, displayName: 'LogProps(${_logPropsHoc.type.displayName})');
203
+ ///
204
+ /// // ---------- Component Consumption ----------
205
+ /// void main() {
206
+ /// setClientConfiguration();
207
+ /// final ref = react.createRef<Element>();
208
+ ///
209
+ /// react_dom.render(LogProps({'component': FancyButton, 'ref': ref}),
210
+ /// querySelector('#idOfSomeNodeInTheDom'));
211
+ ///
212
+ /// // You can still get a ref directly to the DOM button:
213
+ /// final buttonNode = ref.current;
214
+ /// }
215
+ /// ```
135
216
/// See: <https://reactjs.org/docs/forwarding-refs.html>.
136
- ReactJsComponentFactoryProxy forwardRef (Function (Map props, Ref ref) wrapperFunction) {
137
- var hoc = React .forwardRef (allowInterop ((JsMap props, JsRef ref) {
217
+ ReactJsComponentFactoryProxy forwardRef (
218
+ Function (Map props, Ref ref) wrapperFunction, {
219
+ String displayName = 'Anonymous' ,
220
+ }) {
221
+ final wrappedComponent = allowInterop ((JsMap props, JsRef ref) {
138
222
final dartProps = JsBackedMap .backedBy (props);
223
+ for (var value in dartProps.values) {
224
+ if (value is Function ) {
225
+ // Tag functions that came straight from the JS
226
+ // so that we know to pass them through as-is during prop conversion.
227
+ isRawJsFunctionFromProps[value] = true ;
228
+ }
229
+ }
230
+
139
231
final dartRef = Ref .fromJs (ref);
140
232
return wrapperFunction (dartProps, dartRef);
141
- }));
233
+ });
234
+ defineProperty (wrappedComponent, 'displayName' , jsify ({'value' : displayName}));
235
+
236
+ var hoc = React .forwardRef (wrappedComponent);
142
237
143
- return new ReactJsComponentFactoryProxy (hoc, shouldConvertDomProps : false );
238
+ return ReactJsComponentFactoryProxy (hoc);
144
239
}
145
240
146
241
abstract class ReactDom {
0 commit comments