Rohan Sircar
4 years ago
19 changed files with 627 additions and 83 deletions
-
1.gitignore
-
19build.sbt
-
80client/src/main/scala/com/example/playscalajsreact/ScalaJSExample.scala
-
63client/src/main/scala/com/example/playscalajsreact/component/Content.scala
-
8client/src/main/scala/com/example/playscalajsreact/component/HelloWorldComponent.scala
-
25client/src/main/scala/com/example/playscalajsreact/component/IntEditor.scala
-
54client/src/main/scala/com/example/playscalajsreact/component/MenuComponent.scala
-
58client/src/main/scala/com/example/playscalajsreact/component/Middle.scala
-
47client/src/main/scala/com/example/playscalajsreact/component/NameChanger.scala
-
170client/src/main/scala/com/example/playscalajsreact/component/Top.scala
-
19client/src/main/scala/com/example/playscalajsreact/model/Data.scala
-
19client/src/main/scala/com/example/playscalajsreact/model/GlobalState.scala
-
53client/src/main/scala/com/example/playscalajsreact/model/SnapshotTest.scala
-
13client/src/main/scala/com/example/playscalajsreact/model/User.scala
-
61client/src/main/scala/com/example/playscalajsreact/route/AppRouter.scala
-
15client/src/main/scala/com/example/playscalajsreact/route/Page.scala
-
2project/plugins.sbt
-
1server/conf/routes
-
2shared/src/main/scala/com/example/playscalajsreact/shared/SharedMessages.scala
@ -0,0 +1,63 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
|
||||
|
import com.example.playscalajsreact.model.MyGlobalState |
||||
|
import japgolly.scalajs.react.vdom.VdomElement |
||||
|
import japgolly.scalajs.react.Callback |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import com.example.playscalajsreact.route.AppRouter |
||||
|
import org.scalajs.dom |
||||
|
import scala.scalajs.js |
||||
|
import com.example.playscalajsreact.model.User |
||||
|
import japgolly.scalajs.react.extra.StateSnapshot |
||||
|
import com.softwaremill.quicklens._ |
||||
|
import monocle.macros.Lenses |
||||
|
|
||||
|
object Content { |
||||
|
|
||||
|
import scala.concurrent.ExecutionContext.Implicits.global |
||||
|
|
||||
|
final case class State(myGlobalState: MyGlobalState = MyGlobalState()) |
||||
|
|
||||
|
final class Backend($ : BackendScope[_, State]) { |
||||
|
val modifyState = modify[State](_.myGlobalState) |
||||
|
val modifyUsername = modifyState andThenModify MyGlobalState.modifyUsername |
||||
|
var interval: js.UndefOr[js.timers.SetIntervalHandle] = |
||||
|
js.undefined |
||||
|
|
||||
|
def render(s: State): VdomElement = |
||||
|
// MyGlobalState.ctx.provide(s.myGlobalState) { |
||||
|
// <.div(AppRouter.router(AppRouter.Props(s.myGlobalState))) |
||||
|
// } |
||||
|
<.div |
||||
|
|
||||
|
val updateState = (s: State) => { |
||||
|
val direct = $.withEffectsImpure |
||||
|
direct.modState(modifyUsername.using(_ + "C")) |
||||
|
} |
||||
|
|
||||
|
val refresh = (s: State) => |
||||
|
Callback { |
||||
|
interval = js.timers.setInterval(1000) { |
||||
|
updateState(s) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val clear = Callback { |
||||
|
interval foreach js.timers.clearInterval |
||||
|
interval = js.undefined |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
private val component = ScalaComponent |
||||
|
.builder[Unit]("content") |
||||
|
.initialState(State()) |
||||
|
.renderBackend[Backend] |
||||
|
.componentDidMount($ => $.backend.refresh($.state)) |
||||
|
.componentWillUnmount(_.backend.clear) |
||||
|
.build |
||||
|
|
||||
|
def apply() = component() |
||||
|
} |
||||
|
|
@ -0,0 +1,25 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
|
||||
|
object IntEditor { |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import japgolly.scalajs.react.MonocleReact._ |
||||
|
import japgolly.scalajs.react.extra._ |
||||
|
import monocle.macros.Lenses |
||||
|
|
||||
|
val component = ScalaComponent |
||||
|
.builder[StateSnapshot[Int]] |
||||
|
.render_P { stateSnapshot => |
||||
|
<.span( |
||||
|
^.paddingLeft := "6ex", // leave some space for ReusabilityOverlay |
||||
|
<.button( |
||||
|
s"Current value is ${stateSnapshot.value}. Click to increment", |
||||
|
^.onClick --> stateSnapshot.modState(_ + 1), |
||||
|
) |
||||
|
) |
||||
|
} |
||||
|
.configure(ReusabilityOverlay.install) |
||||
|
.build |
||||
|
|
||||
|
def apply(ss: StateSnapshot[Int]) = component(ss) |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
import com.example.playscalajsreact.model.MyGlobalState |
||||
|
import japgolly.scalajs.react.vdom.VdomElement |
||||
|
import japgolly.scalajs.react.Callback |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import com.example.playscalajsreact.route.AppRouter |
||||
|
import japgolly.scalajs.react.extra.router.RouterCtl |
||||
|
import com.example.playscalajsreact.route.Page |
||||
|
import com.example.playscalajsreact.route.Page._ |
||||
|
import japgolly.scalajs.react.extra.StateSnapshot |
||||
|
import com.example.playscalajsreact.model.User |
||||
|
|
||||
|
object MenuComponent { |
||||
|
case class State(myGlobalState: MyGlobalState = MyGlobalState()) |
||||
|
case class Props(state: StateSnapshot[MyGlobalState], c: RouterCtl[Page]) |
||||
|
|
||||
|
class Backend($ : BackendScope[Props, Unit]) { |
||||
|
|
||||
|
def render(props: Props): VdomElement = |
||||
|
{ |
||||
|
val name = props.state.value.user.getOrElse(User.empty).username |
||||
|
<.ul( |
||||
|
Array( |
||||
|
Menu("Home", Home), |
||||
|
Menu("Hello", Hello), |
||||
|
Menu(name, Person(name, 0)), |
||||
|
Menu("Editor", Editor), |
||||
|
Menu("Test", Test) |
||||
|
).toTagMod { item => |
||||
|
{ |
||||
|
<.li( |
||||
|
^.key := item.name, |
||||
|
<.a( |
||||
|
item.name, |
||||
|
props.c setOnClick item.route, |
||||
|
^.color := "red" |
||||
|
) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private val component = ScalaComponent |
||||
|
.builder[Props]("menu") |
||||
|
// .initialState(State()) |
||||
|
.renderBackend[Backend] |
||||
|
// .componentDidMount($ => $.backend.refresh($.state)) |
||||
|
.build |
||||
|
|
||||
|
def apply(state: StateSnapshot[MyGlobalState], c: RouterCtl[Page]) = component(Props(state, c)) |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
|
||||
|
import com.example.playscalajsreact.model.MyGlobalState |
||||
|
import japgolly.scalajs.react.vdom.VdomElement |
||||
|
import japgolly.scalajs.react.Callback |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import com.example.playscalajsreact.route.AppRouter |
||||
|
import org.scalajs.dom |
||||
|
import scala.scalajs.js |
||||
|
import com.example.playscalajsreact.model.User |
||||
|
import japgolly.scalajs.react.extra.StateSnapshot |
||||
|
import com.softwaremill.quicklens._ |
||||
|
import monocle.macros.Lenses |
||||
|
import com.example.playscalajsreact.model._ |
||||
|
import japgolly.scalajs.react.MonocleReact._ |
||||
|
|
||||
|
object Middle { |
||||
|
|
||||
|
final case class Props(name: String, ss: StateSnapshot[Data]) { |
||||
|
@inline def render: VdomElement = Comp(this) |
||||
|
} |
||||
|
|
||||
|
implicit def reusability: Reusability[Props] = |
||||
|
Reusability.derive |
||||
|
|
||||
|
final class Backend($ : BackendScope[Props, Unit]) { |
||||
|
|
||||
|
// Method 2: StateSnapshot.withReuse.zoomL.prepareViaProps |
||||
|
// Notice that we're using a normal lens here instead of a Reusable[lens] |
||||
|
private val ssStrFn = |
||||
|
StateSnapshot.withReuse.zoomL(Data.str).prepareViaProps($)(_.ss) |
||||
|
|
||||
|
def render(p: Props): VdomElement = { |
||||
|
|
||||
|
// Method 1: ss.withReuse.zoomStateL |
||||
|
val ssI: StateSnapshot[Int] = p.ss.zoomStateL(Data.reusableLens.int) |
||||
|
|
||||
|
// Method 2: StateSnapshot.withReuse.zoomL.prepareViaProps |
||||
|
val ssS: StateSnapshot[String] = |
||||
|
ssStrFn(p.ss.value) |
||||
|
|
||||
|
<.div( |
||||
|
<.h3(p.name), |
||||
|
<.div("IntEditor: ", IntEditor(ssI)) |
||||
|
// <.div("TextEditor: ", TextEditor(ssS), ^.marginTop := "0.6em")) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val Comp = ScalaComponent |
||||
|
.builder[Props] |
||||
|
.renderBackend[Backend] |
||||
|
.configure(Reusability.shouldComponentUpdate) |
||||
|
.build |
||||
|
|
||||
|
def apply(_props: Props): VdomElement = { Comp(_props) } |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
|
||||
|
import japgolly.scalajs.react.vdom.VdomElement |
||||
|
import japgolly.scalajs.react.Callback |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import com.example.playscalajsreact.route.AppRouter |
||||
|
import org.scalajs.dom |
||||
|
import scala.scalajs.js |
||||
|
import com.example.playscalajsreact.model.User |
||||
|
import japgolly.scalajs.react.extra.StateSnapshot |
||||
|
import com.softwaremill.quicklens._ |
||||
|
import monocle.macros.Lenses |
||||
|
|
||||
|
object NameChanger { |
||||
|
import japgolly.scalajs.react.MonocleReact._ |
||||
|
|
||||
|
@Lenses |
||||
|
case class Name(firstName: String, surname: String) |
||||
|
|
||||
|
val NameChanger = ScalaComponent |
||||
|
.builder[StateSnapshot[String]] |
||||
|
.render_P { stateSnapshot => |
||||
|
<.input.text( |
||||
|
^.value := stateSnapshot.value, |
||||
|
^.onChange ==> ((e: ReactEventFromInput) => |
||||
|
stateSnapshot.setState(e.target.value) |
||||
|
) |
||||
|
) |
||||
|
} |
||||
|
.build |
||||
|
|
||||
|
val Main = ScalaComponent |
||||
|
.builder[Unit] |
||||
|
.initialState(Name("John", "Wick")) |
||||
|
.render { $ => |
||||
|
val name = $.state |
||||
|
val firstNameV = StateSnapshot.zoomL(Name.firstName).of($) |
||||
|
val surnameV = StateSnapshot.zoomL(Name.surname).of($) |
||||
|
<.div( |
||||
|
<.label("First name:", NameChanger(firstNameV)), |
||||
|
<.label("Surname:", NameChanger(surnameV)), |
||||
|
<.p(s"My name is ${name.surname}, ${name.firstName} ${name.surname}.") |
||||
|
) |
||||
|
} |
||||
|
.build |
||||
|
} |
@ -0,0 +1,170 @@ |
|||||
|
package com.example.playscalajsreact.component |
||||
|
|
||||
|
import com.example.playscalajsreact.model.MyGlobalState |
||||
|
import japgolly.scalajs.react.vdom.VdomElement |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import com.example.playscalajsreact.route.AppRouter |
||||
|
import com.example.playscalajsreact.model.User |
||||
|
import japgolly.scalajs.react.extra.StateSnapshot |
||||
|
// import com.softwaremill.quicklens._ |
||||
|
import com.example.playscalajsreact.model._ |
||||
|
|
||||
|
object Top { |
||||
|
|
||||
|
final class Backend($ : BackendScope[Unit, Data]) { |
||||
|
private val setStateFn = |
||||
|
StateSnapshot.withReuse.prepareVia($) |
||||
|
|
||||
|
def render(state: Data): VdomElement = { |
||||
|
val ss = setStateFn(state) |
||||
|
// Middle.Props("Demo", ss).render |
||||
|
Middle(Middle.Props("Demo", ss)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val Comp = ScalaComponent |
||||
|
.builder[Unit] |
||||
|
.initialState(Data(123, "hello")) |
||||
|
.renderBackend[Backend] |
||||
|
.build |
||||
|
} |
||||
|
|
||||
|
object Top2 { |
||||
|
import japgolly.scalajs.react.vdom.all._ |
||||
|
import japgolly.scalajs.react.MonocleReact._ |
||||
|
|
||||
|
final class Backend($ : BackendScope[Unit, MyGlobalState]) { |
||||
|
private val setStateFn = |
||||
|
StateSnapshot.withReuse.prepareVia($) |
||||
|
|
||||
|
def render(state: MyGlobalState): VdomElement = { |
||||
|
// val ss = StateSnapshot.zoomL(MyGlobalState.user)(state).setStateVia($) |
||||
|
|
||||
|
// val ss2 = ss.xmapState(u => Snappy.State(u))(_.user) |
||||
|
// div(Snappy.Props(ss2).render) |
||||
|
val ss = setStateFn(state) |
||||
|
|
||||
|
div( |
||||
|
// Middle2.Props("Middle2", ss).render, |
||||
|
AppRouter.router(AppRouter.Props(ss)), |
||||
|
"Value: ", |
||||
|
state.user.map(_.username) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val Top2Component = ScalaComponent |
||||
|
.builder[Unit]("Top2") |
||||
|
.initialState(MyGlobalState(Some(User("testuser")))) |
||||
|
// .initialState(MyGlobalState.empty) |
||||
|
.renderBackend[Backend] |
||||
|
.build |
||||
|
|
||||
|
def apply(): VdomElement = Top2Component() |
||||
|
} |
||||
|
|
||||
|
object Middle2 { |
||||
|
import japgolly.scalajs.react.MonocleReact._ |
||||
|
import monocle.macros.syntax.lens._ |
||||
|
import monocle.std.option._ |
||||
|
import monocle.macros.GenIso |
||||
|
import cats.implicits._ |
||||
|
|
||||
|
// val navigateToUsername = GenIso[MyGlobalState, Option[User]] |
||||
|
// .composePrism(GenIso[User, String].asPrism.below[Option]) |
||||
|
|
||||
|
val navigateToUsername = |
||||
|
MyGlobalState.user.composePrism(GenIso[User, String].asPrism.below[Option]) |
||||
|
|
||||
|
final case class Props(name: String, ss: StateSnapshot[MyGlobalState]) { |
||||
|
@inline def render: VdomElement = Comp(this) |
||||
|
} |
||||
|
|
||||
|
implicit def reusability: Reusability[Props] = |
||||
|
Reusability.derive |
||||
|
|
||||
|
final class Backend($ : BackendScope[Props, Unit]) { |
||||
|
|
||||
|
// Method 2: StateSnapshot.withReuse.zoomL.prepareViaProps |
||||
|
// Notice that we're using a normal lens here instead of a Reusable[lens] |
||||
|
private val ssStrFn = |
||||
|
StateSnapshot.withReuse.zoomL(MyGlobalState.user).prepareViaProps($)(_.ss) |
||||
|
|
||||
|
def render(p: Props): VdomElement = { |
||||
|
val x = p.ss.zoomStateO(navigateToUsername) |
||||
|
val y = x.map(_.xmapState(_ => 1)(_ => None)) |
||||
|
|
||||
|
// Method 1: ss.withReuse.zoomStateL |
||||
|
// val ssI: StateSnapshot[Int] = p.ss.zoomStateL(Data.reusableLens.int) |
||||
|
|
||||
|
// Method 2: StateSnapshot.withReuse.zoomL.prepareViaProps |
||||
|
// val ssS: StateSnapshot[String] = |
||||
|
// ssStrFn(p.ss.value) |
||||
|
|
||||
|
val ss4 = p.ss.zoomStateL(MyGlobalState.user) |
||||
|
// val ss5 = p.ss.zoomStateO(navigateToUsername.asOptional) |
||||
|
// val ss6 = |
||||
|
// ss5.map(_.xmapState(_.map(n => User(n)))(_.map(u => u.username))) |
||||
|
// ss5.foreach(_.modState(e => e)) |
||||
|
// val x = p.ss.value.lens(_.user.getOrElse(User.empty).username) |
||||
|
// p.ss.zoomStateO() |
||||
|
|
||||
|
val ss2 = ss4.xmapState(u => Snappy.State(u))(_.user) |
||||
|
|
||||
|
<.div( |
||||
|
<.h3(p.name), |
||||
|
<.div("Snappy", Snappy.Props(ss2).render) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val Comp = ScalaComponent |
||||
|
.builder[Props] |
||||
|
.renderBackend[Backend] |
||||
|
// .configure(Reusability.shouldComponentUpdate) |
||||
|
.build |
||||
|
|
||||
|
def apply(_props: Props): VdomElement = { Comp(_props) } |
||||
|
} |
||||
|
|
||||
|
object Snappy { |
||||
|
|
||||
|
final case class Props(state: StateSnapshot[State]) { |
||||
|
@inline def render: VdomElement = Component(this) |
||||
|
} |
||||
|
|
||||
|
//implicit val reusabilityProps: Reusability[Props] = |
||||
|
// Reusability.derive |
||||
|
|
||||
|
final case class State(user: Option[User]) |
||||
|
|
||||
|
object State { |
||||
|
def empty = State(user = None) |
||||
|
|
||||
|
//implicit val reusability: Reusability[State] = |
||||
|
// Reusability.derive |
||||
|
} |
||||
|
|
||||
|
final class Backend($ : BackendScope[Props, Unit]) { |
||||
|
import com.softwaremill.quicklens._ |
||||
|
def render(p: Props): VdomNode = { |
||||
|
val s = p.state.value |
||||
|
<.div("Test", s.user.map(u => { |
||||
|
<.div( |
||||
|
"Username", |
||||
|
u.username, |
||||
|
^.onClick --> p.state.modState( |
||||
|
_.modify(_.user.each.username).using(_ + "c") |
||||
|
) |
||||
|
) |
||||
|
})) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
val Component = ScalaComponent |
||||
|
.builder[Props]("Snappy") |
||||
|
.renderBackend[Backend] |
||||
|
//.configure(Reusability.shouldComponentUpdate) |
||||
|
.build |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.example.playscalajsreact.model |
||||
|
|
||||
|
import monocle.macros.Lenses |
||||
|
import japgolly.scalajs.react.Reusability |
||||
|
import japgolly.scalajs.react.Reusable |
||||
|
|
||||
|
@Lenses |
||||
|
final case class Data(int: Int, str: String) |
||||
|
|
||||
|
object Data { |
||||
|
implicit val reusability: Reusability[Data] = Reusability.derive |
||||
|
|
||||
|
// Here we wrap the lenses in Reusable.byRef so that React can compare setState/modState functions and know when its |
||||
|
// it's got the same lens as a previous render. This is required to make [Method 1] work with Reusability |
||||
|
object reusableLens { |
||||
|
val int = Reusable.byRef(Data.int) |
||||
|
val str = Reusable.byRef(Data.str) |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.example.playscalajsreact.model |
||||
|
|
||||
|
import japgolly.scalajs.react.feature.Context |
||||
|
import japgolly.scalajs.react.React |
||||
|
import com.softwaremill.quicklens._ |
||||
|
import monocle.macros.Lenses |
||||
|
import japgolly.scalajs.react.Reusability |
||||
|
|
||||
|
@Lenses |
||||
|
case class MyGlobalState(user: Option[User] = None, name: String = "") |
||||
|
|
||||
|
object MyGlobalState { |
||||
|
val ctx: Context[MyGlobalState] = React.createContext(MyGlobalState()) |
||||
|
val modifyUsername = modify[MyGlobalState](_.user.each.username) |
||||
|
|
||||
|
implicit val reusability: Reusability[MyGlobalState] = Reusability.derive |
||||
|
|
||||
|
def empty = MyGlobalState(None, "") |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
package com.example.playscalajsreact.model |
||||
|
|
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
|
||||
|
object Top { |
||||
|
|
||||
|
final case class Props() { |
||||
|
@inline def render: VdomElement = Component(this) |
||||
|
} |
||||
|
|
||||
|
//implicit val reusabilityProps: Reusability[Props] = |
||||
|
// Reusability.derive |
||||
|
|
||||
|
final class Backend($: BackendScope[Props, Unit]) { |
||||
|
def render(p: Props): VdomNode = |
||||
|
<.div |
||||
|
} |
||||
|
|
||||
|
val Component = ScalaComponent.builder[Props]("Top") |
||||
|
.renderBackend[Backend] |
||||
|
//.configure(Reusability.shouldComponentUpdate) |
||||
|
.build |
||||
|
|
||||
|
def apply() = Component(Props()) |
||||
|
} |
||||
|
|
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.all._ |
||||
|
|
||||
|
object Test2 { |
||||
|
|
||||
|
final case class Props() |
||||
|
|
||||
|
//implicit val reusabilityProps: Reusability[Props] = |
||||
|
// Reusability.derive |
||||
|
|
||||
|
final class Backend($: BackendScope[Props, Unit]) { |
||||
|
def render(p: Props): VdomNode = |
||||
|
<.div |
||||
|
} |
||||
|
|
||||
|
private val Test2Component = ScalaComponent.builder[Props]("Test2") |
||||
|
.renderBackend[Backend] |
||||
|
//.configure(Reusability.shouldComponentUpdate) |
||||
|
.build |
||||
|
|
||||
|
def apply(): VdomElement = Test2Component(Props()) |
||||
|
} |
||||
|
|
||||
|
object Test3 { |
||||
|
Test2() |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package com.example.playscalajsreact.model |
||||
|
|
||||
|
import monocle.macros.Lenses |
||||
|
import japgolly.scalajs.react.Reusability |
||||
|
|
||||
|
|
||||
|
@Lenses |
||||
|
case class User(username: String) |
||||
|
|
||||
|
object User { |
||||
|
def empty = User("") |
||||
|
implicit val reusability: Reusability[User] = Reusability.derive |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
package com.example.playscalajsreact.route |
||||
|
|
||||
|
import org.scalajs.dom |
||||
|
import japgolly.scalajs.react._ |
||||
|
import japgolly.scalajs.react.vdom.html_<^._ |
||||
|
import japgolly.scalajs.react.extra._ |
||||
|
import japgolly.scalajs.react.extra.router._ |
||||
|
import com.example.playscalajsreact.component.HelloWorldSJSRComponent |
||||
|
import com.example.playscalajsreact.component.MenuComponent |
||||
|
import com.example.playscalajsreact.component.Top |
||||
|
import com.example.playscalajsreact.component.Top2 |
||||
|
import com.example.playscalajsreact.model.MyGlobalState |
||||
|
import com.example.playscalajsreact.component.Middle2 |
||||
|
|
||||
|
|
||||
|
|
||||
|
object AppRouter { |
||||
|
import com.example.playscalajsreact.route.Page._ |
||||
|
|
||||
|
final case class Props(state: StateSnapshot[MyGlobalState]) |
||||
|
|
||||
|
private def layout(c: RouterCtl[Page], r: ResolutionWithProps[Page, Props])( |
||||
|
appState: Props |
||||
|
) = |
||||
|
<.div( |
||||
|
MenuComponent(appState.state, c), |
||||
|
r.renderP(appState) |
||||
|
) |
||||
|
|
||||
|
val x = <.ol( |
||||
|
^.id := "my-list", |
||||
|
^.lang := "en", |
||||
|
^.margin := 8.px, |
||||
|
<.li("Item 1"), |
||||
|
<.li("Item 2") |
||||
|
// HelloWorldSJSRComponent("Hello", 18) |
||||
|
) |
||||
|
|
||||
|
val routerConfig = RouterWithPropsConfigDsl[Page, Props].buildConfig { dsl => |
||||
|
import dsl._ |
||||
|
(emptyRule |
||||
|
| staticRoute(root, Home) ~> render(x) |
||||
|
| dynamicRouteCT( |
||||
|
("#user" / string("[a-zA-Z0-9]{1,20}") / "age" / int) |
||||
|
.caseClass[Person] |
||||
|
) ~> dynRender((page: Person) => { |
||||
|
HelloWorldSJSRComponent(page.user, page.age) |
||||
|
}) |
||||
|
| staticRoute("#hello", Hello) ~> render(<.div("TODO")) |
||||
|
| staticRoute("#editor", Editor) ~> render(Top.Comp()) |
||||
|
| staticRoute("#test", Test) ~> renderP(p => Middle2.Props("Aege", p.state).render) |
||||
|
| staticRedirect("#hey") ~> redirectToPage(Hello)( |
||||
|
SetRouteVia.HistoryReplace |
||||
|
)) |
||||
|
.notFound(redirectToPage(Home)(SetRouteVia.HistoryReplace)) |
||||
|
.renderWithP(layout) |
||||
|
} |
||||
|
|
||||
|
val router = |
||||
|
RouterWithProps(BaseUrl.fromWindowOrigin / "index", AppRouter.routerConfig) |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package com.example.playscalajsreact.route |
||||
|
|
||||
|
sealed trait Page |
||||
|
object Page { |
||||
|
case object Home extends Page |
||||
|
case object Hello extends Page |
||||
|
case class Person(user: String, age: Int) extends Page |
||||
|
case class ID(id: Int) extends Page |
||||
|
|
||||
|
case class Menu(name: String, route: Page) |
||||
|
case class Product(category: Int, item: Int) extends Page |
||||
|
case class Item(category: String, itemId: java.util.UUID) extends Page |
||||
|
case object Editor extends Page |
||||
|
case object Test extends Page |
||||
|
} |
@ -1,5 +1,5 @@ |
|||||
package com.example.playscalajsreact.shared |
package com.example.playscalajsreact.shared |
||||
|
|
||||
object SharedMessages { |
object SharedMessages { |
||||
def itWorks = "It works!" |
|
||||
|
def itWorks = "It works too!" |
||||
} |
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue