Skip to content

Instantly share code, notes, and snippets.

@rleibman
Last active February 4, 2019 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rleibman/f4e71cfcbafef8c45c12443a5a995bb7 to your computer and use it in GitHub Desktop.
Save rleibman/f4e71cfcbafef8c45c12443a5a995bb7 to your computer and use it in GitHub Desktop.
First pass at a scala.js react toastr
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