diff --git a/README.md b/README.md index bce07f2..49cb28f 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,11 @@ ReactDOM.render(<.div(^.id := "hello-world")("Hello, World!"), mountNode) 2. Depend on the libraries. ``` libraryDependencies ++= Seq( - "io.github.shogowada" %%% "scalajs-reactjs" % "0.13.1", // For react facade - "io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.13.1", // Optional. For react-router-dom facade - "io.github.shogowada" %%% "scalajs-reactjs-router-redux" % "0.13.1", // Optional. For react-router-redux facade - "io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.13.1", // Optional. For react-redux facade - "io.github.shogowada" %%% "scalajs-reactjs-redux-devtools" % "0.13.1" // Optional. For redux-devtools facade + "io.github.shogowada" %%% "scalajs-reactjs" % "0.14.0", // For react facade + "io.github.shogowada" %%% "scalajs-reactjs-router-dom" % "0.14.0", // Optional. For react-router-dom facade + "io.github.shogowada" %%% "scalajs-reactjs-router-redux" % "0.14.0", // Optional. For react-router-redux facade + "io.github.shogowada" %%% "scalajs-reactjs-redux" % "0.14.0", // Optional. For react-redux facade + "io.github.shogowada" %%% "scalajs-reactjs-redux-devtools" % "0.14.0" // Optional. For redux-devtools facade ) ``` diff --git a/build.sbt b/build.sbt index 4a2c2f1..cf7dd44 100644 --- a/build.sbt +++ b/build.sbt @@ -28,7 +28,7 @@ publishArtifact := false val commonSettings = Seq( organization := "io.github.shogowada", name := "scalajs-reactjs", - version := "0.13.1", + version := "0.14.0", licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")), homepage := Some(url("https://github.com/shogowada/scalajs-reactjs")), scalaVersion := "2.12.2", diff --git a/example/redux-devtools/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/devtools/Main.scala b/example/redux-devtools/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/devtools/Main.scala index 1d5ebf7..cb2c6ee 100644 --- a/example/redux-devtools/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/devtools/Main.scala +++ b/example/redux-devtools/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/devtools/Main.scala @@ -1,5 +1,6 @@ package io.github.shogowada.scalajs.reactjs.example.redux.devtools +import io.github.shogowada.scalajs.reactjs.React.Props import io.github.shogowada.scalajs.reactjs.VirtualDOM._ import io.github.shogowada.scalajs.reactjs.classes.ReactClass import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent @@ -49,7 +50,7 @@ object TextContainerComponent { def apply(): ReactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val onTextChange = (text: String) => dispatch(SetText(text)) - (state: State, ownProps: Unit) => { + (state: State, ownProps: Props[Unit]) => { WrappedProps( text = state.text, onTextChange = onTextChange diff --git a/example/redux-middleware/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/middleware/Main.scala b/example/redux-middleware/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/middleware/Main.scala index 275d7c2..91e9ff9 100644 --- a/example/redux-middleware/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/middleware/Main.scala +++ b/example/redux-middleware/src/main/scala/io/github/shogowada/scalajs/reactjs/example/redux/middleware/Main.scala @@ -1,5 +1,6 @@ package io.github.shogowada.scalajs.reactjs.example.redux.middleware +import io.github.shogowada.scalajs.reactjs.React.Props import io.github.shogowada.scalajs.reactjs.VirtualDOM._ import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent import io.github.shogowada.scalajs.reactjs.redux.ReactRedux._ @@ -139,7 +140,7 @@ object Example { val onAddFuture = (value: Int) => dispatch(Future(Add(value))) val onAddFutureFailure = (value: Int) => dispatch(Future.failed(new Exception("This is a test. Do not panic."))) val onSubtract = (value: Int) => dispatch(Subtract(value)) - (state: State, ownProps: Unit) => { + (state: State, ownProps: Props[Unit]) => { ExamplePresentational.WrappedProps( result = state.result, snapshot = state.snapshot, diff --git a/example/router-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/router/redux/Main.scala b/example/router-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/router/redux/Main.scala index 011e00d..29b82d6 100644 --- a/example/router-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/router/redux/Main.scala +++ b/example/router-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/router/redux/Main.scala @@ -1,8 +1,9 @@ package io.github.shogowada.scalajs.reactjs.example.router.redux import io.github.shogowada.scalajs.history.History +import io.github.shogowada.scalajs.reactjs.React.Props import io.github.shogowada.scalajs.reactjs.VirtualDOM._ -import io.github.shogowada.scalajs.reactjs.events.{FormSyntheticEvent, SyntheticEvent} +import io.github.shogowada.scalajs.reactjs.events.FormSyntheticEvent import io.github.shogowada.scalajs.reactjs.redux.ReactRedux._ import io.github.shogowada.scalajs.reactjs.redux.Redux.Dispatch import io.github.shogowada.scalajs.reactjs.redux.devtools.ReduxDevTools @@ -111,32 +112,55 @@ object Main extends JSApp { } } -object RouteControllerComponent { +/* +* Extend RouterProps to access router props (e.g. props.location, props.history, and props.match) +* */ +object RouteControllerComponent extends RouterProps { + lazy val reactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val act = (action: NativeAction) => dispatch(action) - (state: State, ownProps: Unit) => { - RouteControllerPresentationalComponent.WrappedProps(act) + val pushRouteA = () => dispatch(Push("/a")) + val pushRouteB = () => dispatch(Push("/b")) + val goNegative3 = () => dispatch(Go(-1)) + val goBack = () => dispatch(GoBack()) + val goForward = () => dispatch(GoForward()) + (state: State, ownProps: Props[Unit]) => { + RouteControllerPresentationalComponent.WrappedProps( + path = ownProps.location.pathname, + onPushRouteAClick = pushRouteA, + onPushRouteBClick = pushRouteB, + onGoNegative3Click = goNegative3, + onGoBackClick = goBack, + onGoForwardClick = goForward + ) } } )(RouteControllerPresentationalComponent.reactClass) } -object RouteControllerPresentationalComponent extends RouterProps { - case class WrappedProps(act: (NativeAction) => _) +object RouteControllerPresentationalComponent { + case class WrappedProps( + path: String, + onPushRouteAClick: () => _, + onPushRouteBClick: () => _, + onGoNegative3Click: () => _, + onGoBackClick: () => _, + onGoForwardClick: () => _ + ) type Self = React.Self[WrappedProps, Unit] lazy val reactClass = React.createClass[WrappedProps, Unit]( (self) => <.div()( - <.h3()("Path: ", <.span(^.id := "path")(self.props.location.pathname)), + <.h3()("Path: ", <.span(^.id := "path")(self.props.wrapped.path)), <.div()( - <.button(^.id := "push-route-a", ^.onClick := act(self, Push("/a")))("Push route A"), - <.button(^.id := "push-route-b", ^.onClick := act(self, Push("/b")))("Push route B"), - <.button(^.id := "go-negative-3", ^.onClick := act(self, Go(-3)))("Go -3"), - <.button(^.id := "go-back", ^.onClick := act(self, GoBack()))("Go back"), - <.button(^.id := "go-forward", ^.onClick := act(self, GoForward()))("Go forward") + <.button(^.id := "push-route-a", ^.onClick := self.props.wrapped.onPushRouteAClick)("Push route A"), + <.button(^.id := "push-route-b", ^.onClick := self.props.wrapped.onPushRouteBClick)("Push route B"), + <.button(^.id := "go-negative-3", ^.onClick := self.props.wrapped.onGoNegative3Click)("Go -3"), + <.button(^.id := "go-back", ^.onClick := self.props.wrapped.onGoBackClick)("Go back"), + <.button(^.id := "go-forward", ^.onClick := self.props.wrapped.onGoForwardClick)("Go forward") ), <.Switch()( <.Route(^.path := "/a", ^.component := ARouteComponent.reactClass)(), @@ -144,19 +168,13 @@ object RouteControllerPresentationalComponent extends RouterProps { ) ) ) - - private def act(self: Self, action: NativeAction) = - (event: SyntheticEvent) => { - event.preventDefault() - self.props.wrapped.act(action) - } } object ARouteComponent { lazy val reactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val onTextChange = (text: String) => dispatch(ChangeTextA(text)) - (state: State, ownProps: Unit) => { + (state: State, ownProps: Props[Unit]) => { RoutePresentationalComponent.WrappedProps( text = state.wrapped.textA, onTextChange = onTextChange @@ -170,7 +188,7 @@ object BRouteComponent { lazy val reactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val onTextChange = (text: String) => dispatch(ChangeTextB(text)) - (state: State, ownProps: Unit) => { + (state: State, ownProps: Props[Unit]) => { RoutePresentationalComponent.WrappedProps( text = state.wrapped.textB, onTextChange = onTextChange diff --git a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala index 3ee8bac..48e89ab 100644 --- a/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala +++ b/example/todo-app-redux/src/main/scala/io/github/shogowada/scalajs/reactjs/example/todoappredux/ContainerComponents.scala @@ -1,5 +1,6 @@ package io.github.shogowada.scalajs.reactjs.example.todoappredux +import io.github.shogowada.scalajs.reactjs.React.Props import io.github.shogowada.scalajs.reactjs.classes.ReactClass import io.github.shogowada.scalajs.reactjs.redux.ReactRedux import io.github.shogowada.scalajs.reactjs.redux.Redux.Dispatch @@ -24,8 +25,8 @@ object ContainerComponents { var ownProps: LinkContainerComponentOwnProps = null val onClick: () => Unit = () => dispatch(SetVisibilityFilter(filter = ownProps.filter)) - (state: State, nextOwnProps: LinkContainerComponentOwnProps) => { - ownProps = nextOwnProps + (state: State, nextOwnProps: Props[LinkContainerComponentOwnProps]) => { + ownProps = nextOwnProps.wrapped Link.WrappedProps( active = ownProps.filter == state.visibilityFilter, onClick = onClick @@ -37,7 +38,7 @@ object ContainerComponents { def TodoListContainerComponent: ReactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val onTodoClick: (Int) => Unit = (id: Int) => dispatch(ToggleTodo(id = id)) - (state: State, ownProps: Unit) => { + (state: State, ownProps: Props[Unit]) => { TodoList.WrappedProps( todos = state.visibilityFilter match { case VisibilityFilters.ShowAll => state.todos @@ -53,7 +54,7 @@ object ContainerComponents { def AddTodoContainerComponent: ReactClass = ReactRedux.connectAdvanced( (dispatch: Dispatch) => { val onAddTodo: (String) => Unit = (text: String) => dispatch(AddTodo(text = text)) - (state: State, ownProps: Unit) => + (state: State, ownProps: Props[Unit]) => AddTodoComponent.WrappedProps( onAddTodo = onAddTodo ) diff --git a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala index e7de9a3..de10337 100644 --- a/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala +++ b/redux/src/main/scala/io/github/shogowada/scalajs/reactjs/redux/ReactRedux.scala @@ -31,7 +31,7 @@ object ReactRedux { } def connectAdvanced[ReduxState, OwnProps, WrappedProps]( - selectorFactory: Dispatch => (ReduxState, OwnProps) => WrappedProps + selectorFactory: Dispatch => (ReduxState, Props[OwnProps]) => WrappedProps ): ContainerComponentFactory[WrappedProps] = { val nativeSelectorFactory = selectorFactoryToNative(selectorFactory) @@ -40,7 +40,7 @@ object ReactRedux { } private def selectorFactoryToNative[ReduxState, OwnProps, WrappedProps]( - selectorFactory: Dispatch => (ReduxState, OwnProps) => WrappedProps + selectorFactory: Dispatch => (ReduxState, Props[OwnProps]) => WrappedProps ): js.Function1[NativeDispatch, js.Function2[ReduxState, js.Dynamic, js.Any]] = (nativeDispatch: NativeDispatch) => { val dispatch: Dispatch = ReduxInternal.dispatchFromNative(nativeDispatch) @@ -49,10 +49,10 @@ object ReactRedux { } private def selectorToNative[ReduxState, OwnProps, WrappedProps]( - selector: (ReduxState, OwnProps) => WrappedProps + selector: (ReduxState, Props[OwnProps]) => WrappedProps ): js.Function2[ReduxState, js.Dynamic, js.Any] = (state: ReduxState, nativeOwnProps: js.Dynamic) => { - val ownProps: OwnProps = Props(nativeOwnProps).wrapped + val ownProps: Props[OwnProps] = Props(nativeOwnProps) val wrappedProps: WrappedProps = selector(state, ownProps) val nativeProps = clone(nativeOwnProps) nativeProps.updateDynamic(React.WrappedProperty)(wrappedProps.asInstanceOf[js.Any])