Skip to content

Commit d78b1db

Browse files
committed
interop with thirdparty doc
1 parent b1a8705 commit d78b1db

File tree

2 files changed

+123
-91
lines changed

2 files changed

+123
-91
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ Sri (Scalajs React interface) is a scalajs library to build truly native cross p
1616
- [Functions as Components](./docs/StatelessFunctionComponents.md)
1717
- [Navigation](./docs/Navigation.md)
1818
- [Refs To Components](./docs/RefsToComponents.md)
19-
- [Universal Styles](./docs/UniversalStyles.md)
19+
- [Universal Styles](./docs/UniversalStyles.md)
20+
- [Interop With ThirdParty Components](./docs/InteropWithThirdParty.md)

docs/InteropWithThirdParty.md

Lines changed: 121 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Interop With Third Party Components
22

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.
44

55
## Example
66
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
1313
}
1414

1515
```
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
3919

40-
```scala
4120

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
5422

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+
}
5955

60-
}
56+
}
6157

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+
}
6377

64-
hola you successfully created wrapper! :)
78+
}
79+
80+
//usage
81+
82+
AwesomeJS(numberOfLines = 4,testID = "hello");
6583

66-
To use this add original js comp source to jsDependencies in sbt build file/or what ever build tool you use.
84+
```
6785

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
6987

70-
```scala
71-
def render() = View(key= "1")(AwesomeJSCmpWrapper(numberOfLines = 3,testID = "id"))
72-
```
88+
### Using ScalaJSDefined traits
7389

90+
```scala
7491

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.|
75100

76-
## Refs
101+
//first import the js component lib , let say if jslib available as npm package `awesome-js-comp`
77102

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]
79106

80-
Lets assume that our AwesomeJSComp has public method hideMe()
81107

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
83114

84-
```js
85-
// pseudo code
86-
<div>
87-
<AwesomeJSComp ref = "awesomecomp",..props > </AwesomeJSComp>
88-
</div>
115+
}
89116

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)
92127
}
93128

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+
}
104130

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)
118144
}
145+
119146
}
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+
})
123155

124156

125-
```
157+
```
126158

127-
##Real World Examples
128159

129-
https://github.com/chandu0101/sri/tree/master/universal/src/main/scala/sri/universal/components
160+
##Real World Examples
130161

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

Comments
 (0)