Last active
February 4, 2019 19:52
-
-
Save rleibman/f4e71cfcbafef8c45c12443a5a995bb7 to your computer and use it in GitHub Desktop.
First pass at a scala.js react toastr
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
package net.leibman.react | |
import chandu0101.scalajs.react.components.semanticui.{ SuiIcon, SuiIconType } | |
import japgolly.scalajs.react.vdom.html_<^._ | |
import japgolly.scalajs.react.{ BackendScope, Callback, Ref, ScalaComponent } | |
import scala.concurrent.duration.{ Duration, _ } | |
import scala.scalajs.js.timers._ | |
object HorizontalPosition extends Enumeration { | |
type HorizontalPosition = Value | |
val right, center, left = Value | |
} | |
object VerticalPosition extends Enumeration { | |
type VerticalPosition = Value | |
val top, middle, bottom = Value | |
} | |
object Toast { | |
import HorizontalPosition._ | |
import VerticalPosition._ | |
private case class Toast(icon: String = "", | |
className: String = "toast", | |
message: String = "", | |
position: (VerticalPosition, HorizontalPosition) = (top, right)) | |
private case class ToastState(toasts: Seq[Toast] = Seq.empty) | |
class Backend($ : BackendScope[Unit, ToastState]) { | |
def toastMsg(message: String, | |
icon: String, | |
className: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)): Callback = { | |
val newToast = Toast(icon, className, message, position) | |
val ret = $.modState(s => s.copy(toasts = s.toasts :+ newToast)) | |
deleteToastAfterTimeout(newToast, duration) | |
ret | |
} | |
def deleteToastAfterTimeout(newToast: Toast, duration: Duration): SetTimeoutHandle = | |
setTimeout(duration.toMillis) { | |
$.modState(s => s.copy(toasts = s.toasts.filter(_ != newToast))).runNow() | |
} | |
//TODO group by position, make a special div for each position. | |
def render(state: ToastState) = | |
<.div( | |
^.className := "toast", | |
^.boxSizing := "border-box", | |
^.maxHeight := 100.pct, | |
^.overflowX := "hidden", | |
^.overflowY := "auto", | |
^.pointerEvents := "auto", | |
^.position := "fixed", | |
^.top := 0.px, | |
^.right := 0.px, | |
^.padding := 8.px, | |
if (state.toasts.isEmpty) { | |
EmptyVdom | |
} else { | |
state.toasts.zipWithIndex.toVdomArray { | |
case (toast, index) => | |
<.div( | |
^.key := s"toast$index", | |
^.className := s"${toast.className}", | |
<.div(^.className := "iconRegion", | |
<.div(^.className := "countdown", ^.opacity := "0"), | |
SuiIcon(className = "icon", name = SuiIconType(toast.icon))()), | |
<.div(^.className := "textRegion", toast.message), | |
<.div(^.className := "closeButtonRegion", | |
^.role := "button", | |
SuiIcon(name = SuiIconType("close"))(), | |
<.span(^.className := "closeSpan", "Close")) | |
) | |
} | |
} | |
) | |
} | |
private val component = | |
ScalaComponent | |
.builder[Unit]("LeibmanToast") | |
.initialState(ToastState()) | |
.renderBackend[Backend] | |
.build | |
private val toastRef = Ref.toScalaComponent(component) | |
def render() = toastRef.component()() | |
def warning(message: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)): Callback = | |
toast(message, "warning sign", "warning", duration, position) | |
def info(message: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)): Callback = | |
toast(message, "info circle", "info", duration, position) | |
def success(message: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)): Callback = | |
toast(message, "check", "success", duration, position) | |
def error(message: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)): Callback = | |
toast(message, "fire", "error", duration, position) | |
def toast(message: String, | |
icon: String, | |
className: String, | |
duration: Duration = 6 seconds, | |
position: (VerticalPosition, HorizontalPosition) = (top, right)) = | |
toastRef.get | |
.map( | |
_.backend.toastMsg(message, icon, className, duration, position) | |
) | |
.getOrElse(Callback.empty) | |
.flatten | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment