Created
June 24, 2015 19:59
-
-
Save PerWiklander/38791f10b9cd6574b0c0 to your computer and use it in GitHub Desktop.
Traits to simplify making scalajs-react widgets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz.effect.IO | |
trait ItemSelector[ItemType] extends StatefulWidget[ | |
ItemSelectorProps[ItemType], | |
ItemSelectorState[ItemType] | |
] | |
{ | |
override def initialState = P => ItemSelectorState(P.selected) | |
} | |
case class ItemSelectorProps[ItemType]( | |
name: String, | |
items: Seq[ItemType], | |
selected: ItemType, | |
onChange: ItemType => IO[Unit], | |
asValue: ItemType => String = (item: ItemType) => item.toString, | |
asLegend: ItemType => String = (item: ItemType) => item.toString, | |
label: Option[String] = None | |
) | |
case class ItemSelectorState[ItemType]( | |
selected: ItemType | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import japgolly.scalajs.react.ScalazReact._ | |
import japgolly.scalajs.react._ | |
import scalaz.effect.IO | |
import scalaz.syntax.std.boolean._ | |
trait RadioGroup[ItemType] extends ItemSelector[ItemType] { | |
def handleChange(changedItem: ItemType)(implicit scope: Scope): (ReactEventI) => IO[Unit] = | |
(event: ReactEventI) => | |
maybeModifyState( | |
event.target.checked.option(_.copy(selected = changedItem)), | |
scope | |
) | |
override def render = (C, P, S) => { | |
implicit val scope: Scope = C | |
<.div(s.grouped.fields)( | |
P.label map (<.label(_)), | |
P.items map {item => | |
<.div(s.field)( | |
<.div( | |
s.ui.radio.checkbox, | |
item == P.selected ?= s.checked | |
)( | |
<.input( | |
^.tpe := InputType.RADIO, | |
^.value := P.asValue(item), | |
^.checked := item == P.selected, | |
^.name := P.name, | |
^.onChange ~~> handleChange(item) | |
), | |
<.label(P.asLegend(item)) | |
) | |
) | |
} | |
) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import japgolly.scalajs.react.{ReactEventI, ReactElement, ReactComponentB} | |
import japgolly.scalajs.react.ScalazReact.ReactS.Fix | |
import japgolly.scalajs.react.ScalazReact.{ReactS, _} | |
import japgolly.scalajs.react.extra.OnUnmount.Backend | |
import scalaz.effect.IO | |
trait StatefulWidget[Props, State] extends WidgetBase[Props, State, Backend] { | |
protected override val widget: Widget = | |
ReactComponentB[Props](name) | |
.initialStateP(initialState) | |
.backend(_ => new Backend) | |
.renderS(render) | |
.configure(configuration: _*) | |
.componentWillMount(onComponentWillMount) | |
.componentDidMount(onComponentDidMount) | |
.componentWillReceiveProps(onComponentWillReceiveProps) | |
.componentWillUpdate(onComponentWillUpdate) | |
.componentDidUpdate(onComponentDidUpdate) | |
.componentWillUnmount(onComponentWillUnMount) | |
.build | |
protected def initialState: Props => State | |
protected def render: (Scope, Props, State) => ReactElement | |
protected lazy val stateModifier: Fix[State] = ReactS.Fix[State] | |
protected def maybeModifyState( | |
stateModification: Option[State => State], | |
scope: Scope | |
): IO[Unit] = stateModification map (modifyState(_, scope)) getOrElse IO(()) | |
protected def modifyState( | |
stateModification: State => State, | |
scope: Scope | |
): IO[Unit] = scope.runState(stateModifier.mod(stateModification)) | |
protected def modifyStateFromEventTarget( | |
modFromString: String => State => State, | |
scope: Scope | |
) = scope._runState({ event: ReactEventI => stateModifier.mod(modFromString(event.target.value))}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import japgolly.scalajs.react._ | |
/** | |
* Create a widget that always displays the same content, never needs to be redrawn, never needs vdom diffing. | |
*/ | |
trait StaticWidget { | |
private[StaticWidget] val widget = ReactComponentB.static(name, render).buildU | |
def apply(children: ReactElement*) = widget(children) | |
protected def name: String = this.getClass.getSimpleName | |
protected def render: ReactElement | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import japgolly.scalajs.react.{ReactElement, ReactComponentB} | |
trait Widget[Props] extends WidgetBase[Props, Unit, Unit] { | |
protected override val widget: Widget = | |
ReactComponentB[Props](name) | |
.render(render) | |
.configure(configuration: _*) | |
.componentWillMount(onComponentWillMount) | |
.componentDidMount(onComponentDidMount) | |
.componentWillReceiveProps(onComponentWillReceiveProps) | |
.componentWillUpdate(onComponentWillUpdate) | |
.componentDidUpdate(onComponentDidUpdate) | |
.componentWillUnmount(onComponentWillUnMount) | |
.build | |
protected def render: Props => ReactElement | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import japgolly.scalajs.react._ | |
import japgolly.scalajs.react.ReactComponentC.ReqProps | |
import scala.scalajs.js | |
protected trait WidgetBase[Props, State, Backend] { | |
protected type ComponentB = ReactComponentB[Props, State, Backend] | |
protected type ComponentU = ReactComponentU[Props, State, Backend, TopNode] | |
protected type Scope = ComponentScopeU[Props, State, Backend] | |
protected type ScopeM = ComponentScopeM[Props, State, Backend] | |
protected type ScopeWU = ComponentScopeWU[Props, State, Backend] | |
protected type Widget = ReqProps[Props, State, Backend, TopNode] | |
protected def widget: Widget | |
def apply(props: Props, children: ReactNode*): ComponentU = widget(props, children) | |
def withKey(key: js.Any): Widget = widget.set(key = key) | |
def withRef(ref: String): Widget = widget.set(ref = ref) | |
protected def name: String = this.getClass.getSimpleName | |
protected def configuration: Seq[ComponentB => ComponentB] = Seq.empty[ComponentB => ComponentB] | |
protected def onComponentWillMount: Scope => Unit = scope => {} | |
protected def onComponentDidMount: ScopeM => Unit = scope => {} | |
protected def onComponentWillReceiveProps: (ScopeM, Props) => Unit = (scope, props) => {} | |
protected def onComponentWillUpdate: (ScopeWU, Props, State) => Unit = (scope, props, state) => {} | |
protected def onComponentDidUpdate: (ScopeM, Props, State) => Unit = (scope, props, state) => {} | |
protected def onComponentWillUnMount: ScopeM => Unit = scope => {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment