1
1
# Interop With Third Party Components
2
2
3
- If you want to use a reactjs component in your scalajs-react project then you must define a wrapper for js component.
3
+ If you want to use a reactjs component in your project then you must define a wrapper for js component.
4
4
5
5
## Example
6
6
Let say we have a JS component , Name : AwesomeJSComp , props ..
@@ -13,119 +13,150 @@ If you want to use a reactjs component in your scalajs-react project then you mu
13
13
}
14
14
15
15
```
16
- To create a wrapper first we must map js types to scala types
17
-
18
- ``` scala
19
- numberOfLines : Int ,
20
- onPress : js.UndefOr [() => Unit ] = js.undefined,
21
- suppressHighlighting : js.UndefOr [Bool ] = js.undefined,
22
- testID : js.UndefOr [String ] = js.undefined
23
- ```
24
- make sure you have js.UndefOr[ T] for non required fields.we also need a method which converts our scala fields to js.Object
25
-
26
- ``` scala
27
- def toJS = {
28
- val p = js.Dynamic .literal()
29
- p.updateDynamic(" numberOfLines" )(numberOfLines)
30
- onPress.foreach(v => p.updateDynamic(" onPress" )(v))
31
- suppressHighlighting.foreach(v => p.updateDynamic(" suppressHighlighting" )(v))
32
- testID.foreach(v => p.updateDynamic(" testID" )(v))
33
- p
34
- }
35
-
36
- ```
37
-
38
- that's it, now we have all required bits , just composing bits is pending.lets do that
16
+
17
+
18
+ ### Using FunctionObjectMacro
39
19
40
- ``` scala
41
20
42
- case class AwesomeJSCompWrapper ( numberOfLines : Int ,
43
- onPress : js.UndefOr [() => Unit ] = js.undefined,
44
- suppressHighlighting : js.UndefOr [Bool ] = js.undefined,
45
- testID : js.UndefOr [String ] = js.undefined) {
46
- def toJS = {
47
- val p = js.Dynamic .literal()
48
- p.updateDynamic(" numberOfLines" )(numberOfLines)
49
- onPress.foreach(v => p.updateDynamic(" onPress" )(v))
50
- suppressHighlighting.foreach(v => p.updateDynamic(" suppressHighlighting" )(v))
51
- testID.foreach(v => p.updateDynamic(" testID" )(v))
52
- p
53
- }
21
+ ``` scala
54
22
55
- def apply (children : ReactNode * ) = {
56
- val f = React .createFactory(js.Dynamic .Global .AwesomeJSComp ) // access real js component , make sure you wrap with createFactory (this is needed from 0.13 onwards)
57
- f(toJS, children : _* )
58
- }
23
+ import sri .macros .{
24
+ exclude ,
25
+ FunctionObjectMacro ,
26
+ OptDefault => NoValue ,
27
+ OptionalParam => U
28
+ }
29
+ import sri .core .{CreateElementJSNoInline , ReactElement , ReactNode }
30
+ import scala .scalajs .js .JSConverters .genTravConvertible2JSRichGenTrav
31
+ import scala .scalajs .js
32
+ import scala .scalajs .js .annotation .{JSImport }
33
+ import sri .core .{JSComponent }
34
+
35
+ // first import the js component lib , let say if jslib available as npm package `awesome-js-comp`
36
+
37
+ @ js.native
38
+ @ JSImport (" awesome-js-comp" , JSImport .Default )
39
+ object AwesomeJSComp extends JSComponent [js.Object ]
40
+
41
+
42
+ object AwesomeJS {
43
+ @ inline
44
+ def apply (numberOfLines : Int ,
45
+ onPress : U [() => Unit ] = NoValue ,
46
+ suppressHighlighting : U [Boolean ] = NoValue ,
47
+ @ exclude key : String | Int = null ,
48
+ @ exclude ref : js.Function1 [AwesomeJSComp .type , Unit ] = null ,
49
+ testID : U [String ] = NoValue )
50
+ : ReactElement { type Instance = AwesomeJSComp .type } = {
51
+
52
+ val props = FunctionObjectMacro ()
53
+ CreateElementJSNoInline [AwesomeJSComp .type ](AwesomeJSComp , props, key, ref)
54
+ }
59
55
60
- }
56
+ }
61
57
62
- ```
58
+ // if component accepts children
59
+
60
+ object AwesomeJS {
61
+ @ inline
62
+ def apply (numberOfLines : Int ,
63
+ onPress : U [() => Unit ] = NoValue ,
64
+ suppressHighlighting : U [Boolean ] = NoValue ,
65
+ @ exclude key : String | Int = null ,
66
+ @ exclude ref : js.Function1 [AwesomeJSComp .type , Unit ] = null ,
67
+ testID : U [String ] = NoValue )(children : ReactNode * )
68
+ : ReactElement { type Instance = AwesomeJSComp .type } = {
69
+
70
+ val props = FunctionObjectMacro ()
71
+ CreateElementJSNoInline [AwesomeJSComp .type ](AwesomeJSComp ,
72
+ props,
73
+ key,
74
+ ref,
75
+ children.toJSArray)
76
+ }
63
77
64
- hola you successfully created wrapper! :)
78
+ }
79
+
80
+ // usage
81
+
82
+ AwesomeJS (numberOfLines = 4 ,testID = " hello" );
65
83
66
- To use this add original js comp source to jsDependencies in sbt build file/or what ever build tool you use.
84
+ ```
67
85
68
- now you can use AwesomeJSCmpWrapper like a normal component
86
+ *** Note: *** If you're wondering why we're using ` OptionalParam ` instead of ` js.UndefOr ` check this : https://github.com/scala-js/scala-js/issues/2714
69
87
70
- ``` scala
71
- def render () = View (key= " 1" )(AwesomeJSCmpWrapper (numberOfLines = 3 ,testID = " id" ))
72
- ```
88
+ ### Using ScalaJSDefined traits
73
89
90
+ ``` scala
74
91
92
+ import sri .core .{CreateElementJSNoInline , ReactElement , ReactNode }
93
+ import sri .macros .exclude
94
+ import scala .scalajs .js .JSConverters .genTravConvertible2JSRichGenTrav
95
+ import scala .scalajs .js
96
+ import scala .scalajs .js .{UndefOr => U ,undefined }
97
+ import sri .core .{JSComponent }
98
+ import scala .scalajs .js .annotation .{JSImport , ScalaJSDefined }
99
+ import scala .scalajs .js .|
75
100
76
- ## Refs
101
+ // first import the js component lib , let say if jslib available as npm package `awesome-js-comp`
77
102
78
- Some times we may want to call public(exposed) methods of mounted react component's , we use refs to achieve this
103
+ @ js.native
104
+ @ JSImport (" awesome-js-comp" , JSImport .Default )
105
+ object AwesomeJSComp extends JSComponent [AwesomeJSCompProps ]
79
106
80
- Lets assume that our AwesomeJSComp has public method hideMe()
81
107
82
- JS World :
108
+ @ ScalaJSDefined
109
+ trait AwesomeJSCompProps extends js.Object {
110
+ val numberOfLines : Int
111
+ val onPress : U [() => Unit ] = undefined
112
+ val suppressHighlighting : U [Boolean ] = undefined
113
+ val testID : U [String ] = undefined
83
114
84
- ``` js
85
- // pseudo code
86
- < div>
87
- < AwesomeJSComp ref = " awesomecomp" ,..props > < / AwesomeJSComp>
88
- < / div>
115
+ }
89
116
90
- function test () {
91
- this .refs .awesomecomp .hideMe ()
117
+ object AwesomeJS {
118
+ @ inline
119
+ def apply (props : AwesomeJSCompProps ,
120
+ @ exclude key : String | Int = null ,
121
+ @ exclude ref : js.Function1 [AwesomeJSComp .type , Unit ] = null )
122
+ : ReactElement { type Instance = AwesomeJSComp .type } = {
123
+ CreateElementJSNoInline [AwesomeJSComp .type ](AwesomeJSComp ,
124
+ props,
125
+ key,
126
+ ref)
92
127
}
93
128
94
- ```
95
-
96
- Scala World :
97
-
98
- To achieve same thing in scala world ,add a new field ref to our AwesomeJSCompWrapper and then create a facade
99
- for public methods of AwesomeJSComp
100
-
101
- ``` scala
102
- trait AwesomeJSCompWrapperM extends js.Object {
103
- def hideMe () : Unit = js.native
129
+ }
104
130
105
- ... more public methods
106
- }
107
- ```
108
- scala example :
109
- ``` scala
110
- object Parent {
111
- @ ScalaJSDefined
112
- class Component extends ReactComponent [ Unit , Unit ] {
113
- def render () = View (key = " 4 " )( AwesomeJSCompWrapperM (ref = storeChildRef _))
114
- var childRef : AwesomeJSCompWrapperM = _
115
- def storeChildRef ( cref : AwesomeJSCompWrapperM ) = {
116
- childRef = cref // store reference to use later
117
- childRef.hideMe() // invoke actions
131
+ // if component accepts children
132
+ object AwesomeJS {
133
+ @ inline
134
+ def apply ( props : AwesomeJSCompProps ,
135
+ @ exclude key : String | Int = null ,
136
+ @ exclude ref : js. Function1 [ AwesomeJSComp . type , Unit ] = null )(
137
+ children : ReactNode * )
138
+ : ReactElement { type Instance = AwesomeJSComp . type } = {
139
+ CreateElementJSNoInline [ AwesomeJSComp . type ]( AwesomeJSComp ,
140
+ props,
141
+ key,
142
+ ref,
143
+ children.toJSArray)
118
144
}
145
+
119
146
}
120
- def apply (key : js.UndefOr [String ] = js.undefined, ref : js.Function1 [Component ,_] = null ) =
121
- makeElementNoProps[Component ](key = key, ref = ref)
122
- }
147
+
148
+
149
+ // usage
150
+
151
+ AwesomeJS (props = new AwesomeJSCompProps {
152
+ override val numberOfLines : Int = 2
153
+ override val testID : U [String ] = " hello"
154
+ })
123
155
124
156
125
- ```
157
+ ```
126
158
127
- ##Real World Examples
128
159
129
- https://github.com/chandu0101/sri/tree/master/universal/src/main/scala/sri/universal/components
160
+ ##Real World Examples
130
161
131
- https://github.com/chandu0101/sri/tree /master/mobile/ src/main/scala/sri/mobile /components
162
+ https://github.com/scalajs-react-interface/universal/blob /master/src/main/scala/sri/universal /components/UniversalComponents.scala
0 commit comments