@@ -6,7 +6,7 @@ import type { ForwardedRef, ReactChild, ReactNode } from 'react';
6
6
/**
7
7
* WordPress dependencies
8
8
*/
9
- import { forwardRef , memo } from '@wordpress/element' ;
9
+ import { forwardRef } from '@wordpress/element' ;
10
10
import warn from '@wordpress/warning' ;
11
11
12
12
/**
@@ -16,42 +16,74 @@ import { CONNECT_STATIC_NAMESPACE } from './constants';
16
16
import { getStyledClassNameFromKey } from './get-styled-class-name-from-key' ;
17
17
import type { WordPressComponentFromProps } from '.' ;
18
18
19
+ type AcceptsTwoArgs <
20
+ F extends ( ...args : any ) => any ,
21
+ ErrorMessage = never
22
+ > = Parameters < F > [ 'length' ] extends 2 ? { } : ErrorMessage ;
23
+
19
24
type ContextConnectOptions = {
20
- /** Defaults to `false`. */
21
- memo ?: boolean ;
25
+ forwardsRef ?: boolean ;
22
26
} ;
23
27
24
28
/**
25
29
* Forwards ref (React.ForwardRef) and "Connects" (or registers) a component
26
30
* within the Context system under a specified namespace.
27
31
*
28
- * This is an (experimental) evolution of the initial connect() HOC.
29
- * The hope is that we can improve render performance by removing functional
30
- * component wrappers.
32
+ * @param Component The component to register into the Context system.
33
+ * @param namespace The namespace to register the component under.
34
+ * @return The connected WordPressComponent
35
+ */
36
+ export function contextConnect <
37
+ C extends ( props : any , ref : ForwardedRef < any > ) => JSX . Element | null
38
+ > (
39
+ Component : C &
40
+ AcceptsTwoArgs <
41
+ C ,
42
+ 'Warning: Your component function does not take a ref as the second argument. Did you mean to use `contextConnectWithoutRef`?'
43
+ > ,
44
+ namespace : string
45
+ ) {
46
+ return _contextConnect ( Component , namespace , { forwardsRef : true } ) ;
47
+ }
48
+
49
+ /**
50
+ * "Connects" (or registers) a component within the Context system under a specified namespace.
51
+ * Does not forward a ref.
31
52
*
32
53
* @param Component The component to register into the Context system.
33
54
* @param namespace The namespace to register the component under.
34
- * @param options
35
55
* @return The connected WordPressComponent
36
56
*/
37
- export function contextConnect < P > (
38
- Component : ( props : P , ref : ForwardedRef < any > ) => JSX . Element | null ,
39
- namespace : string ,
40
- options : ContextConnectOptions = { }
41
- ) : WordPressComponentFromProps < P > {
42
- const { memo : memoProp = false } = options ;
57
+ export function contextConnectWithoutRef < P > (
58
+ Component : ( props : P ) => JSX . Element | null ,
59
+ namespace : string
60
+ ) {
61
+ return _contextConnect ( Component , namespace ) ;
62
+ }
43
63
44
- let WrappedComponent = forwardRef ( Component ) ;
45
- if ( memoProp ) {
46
- // @ts -ignore
47
- WrappedComponent = memo ( WrappedComponent ) ;
48
- }
64
+ // This is an (experimental) evolution of the initial connect() HOC.
65
+ // The hope is that we can improve render performance by removing functional
66
+ // component wrappers.
67
+ function _contextConnect <
68
+ C extends ( props : any , ref : ForwardedRef < any > ) => JSX . Element | null ,
69
+ O extends ContextConnectOptions
70
+ > (
71
+ Component : C ,
72
+ namespace : string ,
73
+ options ?: O
74
+ ) : WordPressComponentFromProps <
75
+ Parameters < C > [ 0 ] ,
76
+ O [ 'forwardsRef' ] extends true ? true : false
77
+ > {
78
+ const WrappedComponent = options ?. forwardsRef
79
+ ? forwardRef < any , Parameters < C > [ 0 ] > ( Component )
80
+ : Component ;
49
81
50
82
if ( typeof namespace === 'undefined' ) {
51
83
warn ( 'contextConnect: Please provide a namespace' ) ;
52
84
}
53
85
54
- // @ts -ignore internal property
86
+ // @ts -expect-error internal property
55
87
let mergedNamespace = WrappedComponent [ CONNECT_STATIC_NAMESPACE ] || [
56
88
namespace ,
57
89
] ;
@@ -66,18 +98,13 @@ export function contextConnect< P >(
66
98
mergedNamespace = [ ...mergedNamespace , namespace ] ;
67
99
}
68
100
69
- WrappedComponent . displayName = namespace ;
70
-
71
- // @ts -ignore internal property
72
- WrappedComponent [ CONNECT_STATIC_NAMESPACE ] = [
73
- ...new Set ( mergedNamespace ) ,
74
- ] ;
75
-
76
- // @ts -ignore WordPressComponent property
77
- WrappedComponent . selector = `.${ getStyledClassNameFromKey ( namespace ) } ` ;
78
-
79
- // @ts -ignore
80
- return WrappedComponent ;
101
+ // @ts -expect-error We can't rely on inferred types here because of the
102
+ // `as` prop polymorphism we're handling in https://github.com/WordPress/gutenberg/blob/9620bae6fef4fde7cc2b7833f416e240207cda29/packages/components/src/ui/context/wordpress-component.ts#L32-L33
103
+ return Object . assign ( WrappedComponent , {
104
+ [ CONNECT_STATIC_NAMESPACE ] : [ ...new Set ( mergedNamespace ) ] ,
105
+ displayName : namespace ,
106
+ selector : `.${ getStyledClassNameFromKey ( namespace ) } ` ,
107
+ } ) ;
81
108
}
82
109
83
110
/**
0 commit comments