Skip to content

Commit 0e984d1

Browse files
authored
Merge pull request #497 from japgolly/series/v1.3.x
v1.3.x
2 parents 98c47a4 + 1c7efa2 commit 0e984d1

File tree

89 files changed

+2876
-834
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2876
-834
lines changed

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ jdk:
1010

1111
install:
1212
- . $HOME/.nvm/nvm.sh
13-
- nvm install 7
14-
- nvm use 7
13+
- nvm install 10
14+
- nvm use 10
1515
- export NODE_PATH="$(npm config get prefix)"/lib/node_modules
1616
- npm install
17-
- npm install jsdom source-map-support
17+
- npm install jsdom@11 source-map-support
1818

1919
script:
20-
- sbt ++$TRAVIS_SCALA_VERSION test:fastOptJS test:fullOptJS
20+
#- sbt ++$TRAVIS_SCALA_VERSION test:fastOptJS test:fullOptJS
2121
- sbt ++$TRAVIS_SCALA_VERSION 'set parallelExecution in ThisBuild := false' test
2222
- sbt ++$TRAVIS_SCALA_VERSION 'set parallelExecution in ThisBuild := false' 'set scalaJSStage in ThisBuild := FullOptStage' test
2323
- bin/checkDevOnly $TRAVIS_SCALA_VERSION

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version in ThisBuild := "1.2.3"
1+
version in ThisBuild := "1.3.0-SNAPSHOT"
22
organization in ThisBuild := "com.github.japgolly.scalajs-react"
33
homepage in ThisBuild := Some(url("https://github.com/japgolly/scalajs-react"))
44
licenses in ThisBuild := ("Apache-2.0", url("http://opensource.org/licenses/Apache-2.0")) :: Nil

cats/src/main/scala/japgolly/scalajs/react/internal/CatsReactExt.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ object CatsReactExt {
3030
import CatsReactState.{ReactST, ChangeFilter}
3131
import CatsReact.CatsReactExt_StateAccessCB
3232

33-
def listenWithStateMonad[P, C <: Children, S, B <: OnUnmount, M[_], A](listenable: P => Listenable[A],
34-
listener: A => ReactST[M, S, Unit])(implicit M: M ~> CallbackTo, N: Monad[M]) =
35-
Listenable.listen[P, C, S, B, A](listenable, $ => a => $.runState(listener(a)))
36-
37-
def listenWithStateMonadF[P, C <: Children, S, B <: OnUnmount, M[_], A](listenable: P => Listenable[A],
38-
listener: A => ReactST[M, S, Unit])(implicit M: M ~> CallbackTo, N: Monad[M], F: ChangeFilter[S]) =
39-
Listenable.listen[P, C, S, B, A](listenable, $ => a => $.runStateF(listener(a)))
33+
def listenWithStateMonad[P, C <: Children, S, B <: OnUnmount, U <: UpdateSnapshot, M[_], A]
34+
(listenable: P => Listenable[A],
35+
listener: A => ReactST[M, S, Unit])
36+
(implicit M: M ~> CallbackTo, N: Monad[M]) =
37+
Listenable.listen[P, C, S, B, U, A](listenable, $ => a => $.runState(listener(a)))
38+
39+
def listenWithStateMonadF[P, C <: Children, S, B <: OnUnmount, U <: UpdateSnapshot, M[_], A]
40+
(listenable: P => Listenable[A],
41+
listener: A => ReactST[M, S, Unit])
42+
(implicit M: M ~> CallbackTo, N: Monad[M], F: ChangeFilter[S]) =
43+
Listenable.listen[P, C, S, B, U, A](listenable, $ => a => $.runStateF(listener(a)))
4044
}
4145

4246
}

cats/src/main/scala/japgolly/scalajs/react/internal/CatsReactInstances.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,15 @@ trait CatsReactInstances {
113113
case _ => false
114114
}
115115

116+
implicit final lazy val reactRefFnCatsInstance: Profunctor[Ref.Fn] =
117+
new Profunctor[Ref.Fn] {
118+
override def lmap[A, B, C](f: Ref.Fn[A, B])(m: C => A) = f.contramap(m)
119+
override def rmap[A, B, C](f: Ref.Fn[A, B])(m: B => C) = f.map(m)
120+
}
121+
122+
implicit final def reactRefFullCatsInstance[X]: Profunctor[Ref.Full[?, X, ?]] =
123+
new Profunctor[Ref.Full[?, X, ?]] {
124+
override def lmap[A, B, C](f: Ref.Full[A, X, B])(m: C => A) = f.contramap(m)
125+
override def rmap[A, B, C](f: Ref.Full[A, X, B])(m: B => C) = f.map(m)
126+
}
116127
}

core/src/main/scala/japgolly/scalajs/react/Callback.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,4 +747,12 @@ final class CallbackTo[A] private[react] (private[CallbackTo] val f: () => A) ex
747747
*/
748748
def !(implicit ev: CallbackTo[A] <:< CallbackTo[Boolean]): CallbackTo[Boolean] =
749749
ev(this).map(!_)
750+
751+
/** Wraps this so that:
752+
*
753+
* 1) It only executes if `e.defaultPrevented` is `false`.
754+
* 2) It sets `e.preventDefault` on successful completion.
755+
*/
756+
def asEventDefault(e: ReactEvent): CallbackTo[Option[A]] =
757+
(this <* e.preventDefaultCB).unless(e.defaultPrevented)
750758
}

core/src/main/scala/japgolly/scalajs/react/CallbackOption.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,9 @@ object CallbackOption {
138138
* 1) It only executes if `e.defaultPrevented` is `false`.
139139
* 2) It sets `e.preventDefault` on successful completion.
140140
*/
141+
@deprecated("Use callback.asEventDefault(e) instead", "1.3.0")
141142
def asEventDefault[A](e: ReactEvent, co: CallbackOption[A]): CallbackOption[A] =
142-
for {
143-
_ <- unless(e.defaultPrevented)
144-
a <- co
145-
_ <- e.preventDefaultCB.toCBO
146-
} yield a
143+
co.asEventDefault(e)
147144

148145
@inline implicit def callbackOptionCovariance[A, B >: A](c: CallbackOption[A]): CallbackOption[B] =
149146
c.widen
@@ -311,4 +308,12 @@ final class CallbackOption[A](private val cbfn: () => Option[A]) extends AnyVal
311308

312309
def ||[B](b: CallbackOption[B]): CallbackOption[Unit] =
313310
void | b.void
311+
312+
/** Wraps this so that:
313+
*
314+
* 1) It only executes if `e.defaultPrevented` is `false`.
315+
* 2) It sets `e.preventDefault` on successful completion.
316+
*/
317+
def asEventDefault(e: ReactEvent): CallbackOption[A] =
318+
(this <* e.preventDefaultCB.toCBO).unless(e.defaultPrevented)
314319
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package japgolly.scalajs.react
2+
3+
import japgolly.scalajs.react.{raw => Raw}
4+
import org.scalajs.dom
5+
import org.scalajs.dom.html
6+
import scala.scalajs.js.|
7+
8+
sealed trait ComponentDom {
9+
10+
def mounted: Option[ComponentDom.Mounted]
11+
12+
/** unsafe! may throw an exception */
13+
final def asMounted(): ComponentDom.Mounted =
14+
mounted getOrElse sys.error("DOM node isn't mounted.")
15+
16+
def toElement: Option[dom.Element] = None
17+
def toText: Option[dom.Text] = None
18+
19+
final def toHtml: Option[html.Element] =
20+
toElement.flatMap(_.domToHtml)
21+
22+
final def toNode: Option[dom.Node] =
23+
mounted.map(_.node)
24+
25+
@deprecated("Either use .toHtml, or call .mounted and safely handle None before .asHtml()", "1.3.0")
26+
final def domAsHtml: html.Element =
27+
asMounted().asHtml()
28+
29+
@deprecated("Use .toHtml", "1.3.0")
30+
def domToHtml: Option[html.Element] =
31+
toHtml
32+
33+
@deprecated("Call .mounted and safely handle None before .raw", "1.3.0")
34+
def rawDomNode: Raw.ReactDOM.DomNode =
35+
asMounted().raw
36+
37+
@deprecated("Use .toText", "1.3.0")
38+
final def left = toText
39+
40+
@deprecated("Use .toElement", "1.3.0")
41+
final def right = toElement
42+
43+
// These are commented out because the deprecation cascades to usages of the implementations in ComponentDom.Mounted
44+
// which is not what I want. Those versions are fine.
45+
46+
// @deprecated("Either use .toElement, or call .mounted and safely handle None before .asElement", "1.3.0")
47+
// def asElement(): dom.Element =
48+
// asMounted().asElement()
49+
//
50+
// @deprecated("Either use .toText, or call .mounted and safely handle None before .asText", "1.3.0")
51+
// def asText(): dom.Text =
52+
// asMounted().asText()
53+
//
54+
// @deprecated("Call .mounted and safely handle None before .domCast", "1.3.0")
55+
// def domCast[N <: dom.raw.Node]: N =
56+
// asMounted().domCast[N]
57+
//
58+
// @deprecated("Call .mounted and safely handle None before .fold", "1.3.0")
59+
// def fold[A](text: dom.Text => A, element: dom.Element => A): A =
60+
// asMounted().fold(text, element)
61+
}
62+
63+
object ComponentDom {
64+
65+
def apply(i: Raw.ReactDOM.DomNode | Null | Unit): ComponentDom =
66+
(i: Any) match {
67+
case e: dom.Element => Element(e)
68+
case t: dom.Text => Text(t)
69+
case null | () => Unmounted
70+
}
71+
72+
case object Unmounted extends ComponentDom {
73+
override def mounted = None
74+
}
75+
76+
sealed trait Mounted extends ComponentDom {
77+
override def mounted = Some(this)
78+
79+
def node: dom.Node
80+
def raw: Raw.ReactDOM.DomNode
81+
82+
@deprecated("Use .raw", "1.3.0")
83+
final override def rawDomNode: Raw.ReactDOM.DomNode = raw
84+
85+
/** unsafe! may throw an exception */
86+
final def asElement(): dom.Element =
87+
this match {
88+
case Element(e) => e
89+
case Text(t) => sys error s"Expected a dom.Element; got $t"
90+
}
91+
92+
/** unsafe! may throw an exception */
93+
final def domCast[N <: dom.raw.Node]: N =
94+
asElement().domCast[N]
95+
96+
/** unsafe! may throw an exception */
97+
final def asHtml(): html.Element =
98+
asElement().domCast
99+
100+
/** unsafe! may throw an exception */
101+
final def asText(): dom.Text =
102+
this match {
103+
case Text(t) => t
104+
case Element(e) => sys error s"Expected a dom.Text; got $e"
105+
}
106+
107+
def fold[A](text: dom.Text => A, element: dom.Element => A): A
108+
}
109+
110+
final case class Element(element: dom.Element) extends Mounted {
111+
override def toElement = Some(element)
112+
override def node = element
113+
override def raw = element
114+
override def fold[A](text: dom.Text => A, f: dom.Element => A) = f(element)
115+
}
116+
117+
final case class Text(text: dom.Text) extends Mounted {
118+
override def toText = Some(text)
119+
override def node = text
120+
override def raw = text
121+
override def fold[A](f: dom.Text => A, element: dom.Element => A) = f(text)
122+
}
123+
124+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package japgolly.scalajs.react
2+
3+
import japgolly.scalajs.react.internal.{JsRepr, NotAllowed}
4+
import japgolly.scalajs.react.vdom.{VdomElement, VdomNode}
5+
import japgolly.scalajs.react.{raw => Raw}
6+
7+
object React {
8+
@inline def raw = Raw.React
9+
10+
@inline def version: String =
11+
raw.version
12+
13+
/** Create a new context.
14+
*
15+
* If you'd like to retain type information about the JS type used under-the-hood with React,
16+
* use `React.Context(defaultValue)` instead.
17+
*
18+
* @since 1.3.0 / React 16.3.0
19+
*/
20+
def createContext[A](defaultValue: A)(implicit jsRepr: JsRepr[A]): Context[A] =
21+
Context(defaultValue)(jsRepr)
22+
23+
@deprecated("Use Ref. For details see https://github.com/japgolly/scalajs-react/blob/master/doc/REFS.md", "1.3.0 / React 16.3.0")
24+
def createRef(notAllowed: NotAllowed) = NotAllowed.body
25+
26+
type Context[A] = feature.Context[A]
27+
val Context = feature.Context
28+
29+
val Fragment = feature.ReactFragment
30+
31+
/** Ref forwarding is an opt-in feature that lets some components take a ref they receive,
32+
* and pass it further down (in other words, "forward" it) to a child.
33+
*
34+
* See https://reactjs.org/docs/forwarding-refs.html
35+
*/
36+
@inline def forwardRef = component.ReactForwardRef
37+
38+
/** StrictMode is a tool for highlighting potential problems in an application.
39+
* Like Fragment, StrictMode does not render any visible UI.
40+
* It activates additional checks and warnings for its descendants.
41+
*
42+
* Strict mode checks are run in development mode only; they do not impact the production build.
43+
*
44+
* @since 1.3.0 / React 16.3.0
45+
*/
46+
def StrictMode(ns: VdomNode*): VdomElement =
47+
VdomElement(Raw.React.createElement(Raw.React.StrictMode, null, ns.map(_.rawNode): _*))
48+
}
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package japgolly.scalajs.react
22

3-
import japgolly.scalajs.react.component.Generic.MountedDomNode
3+
import japgolly.scalajs.react.internal.NotAllowed
44
import japgolly.scalajs.react.{raw => Raw}
55
import org.scalajs.dom
66
import scala.scalajs.js.|
@@ -9,27 +9,25 @@ object ReactDOM {
99
def raw = Raw.ReactDOM
1010

1111
/** For mounted components, use .getDOMNode */
12-
def findDOMNode(componentOrElement: dom.Element | Raw.React.ComponentUntyped): Option[MountedDomNode] =
13-
MountedDomNode.nullable(raw.findDOMNode(componentOrElement))
12+
def findDOMNode(componentOrElement: dom.Element | Raw.React.ComponentUntyped): Option[ComponentDom.Mounted] =
13+
ComponentDom(raw.findDOMNode(componentOrElement)).mounted
1414

1515
def unmountComponentAtNode(container: dom.Node): Boolean =
1616
raw.unmountComponentAtNode(container)
1717

1818
// .hydrate is not here because currently, SSR with scalajs-react isn't directly supported.
1919
// .raw.hydrate can be used if needed.
2020

21-
sealed trait NotAllowed
22-
2321
// There are three ways of providing this functionality:
2422
// 1. ReactDOM.render here (problem: lose return type precision)
2523
// 2. ReactDOM.render{Js,Scala,Vdom,etc}
2624
// 3. Add .renderIntoDOM to mountable types (current solution)
2725
@deprecated("Use .renderIntoDOM on unmounted components.", "")
2826
def render(element : NotAllowed,
29-
container: NotAllowed,
30-
callback : NotAllowed = null): Null = null
27+
container: Any,
28+
callback : Any = null) = NotAllowed.body
3129

3230
@deprecated("Import vdom and use ReactPortal()", "")
33-
def createPortal(child: NotAllowed, container: NotAllowed): Null = null
31+
def createPortal(child: NotAllowed, container: Any) = NotAllowed.body
3432

3533
}

0 commit comments

Comments
 (0)