All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.udash.bootstrap.button.UdashButton.scala Maven / Gradle / Ivy

There is a newer version: 0.13.0
Show newest version
package io.udash.bootstrap
package button

import io.udash.*
import com.avsystem.commons.Opt
import com.avsystem.commons.misc.AbstractCase
import io.udash.bindings.modifiers.Binding
import io.udash.bootstrap.button.UdashButton.{ButtonClickEvent, ButtonTag, UdashButtonJQuery}
import io.udash.bootstrap.utils.*
import io.udash.wrappers.jquery.{JQuery, jQ}
import org.scalajs.dom
import org.scalajs.dom.*
import scalatags.JsDom
import scalatags.JsDom.all.*
import com.avsystem.commons.SharedExtensions.universalOps

import scala.scalajs.js

/**
 * Options for `UdashButton` component
 *
 * @param color           A button style, one of the standard bootstrap colors `BootstrapStyles.Color`.
 * @param size            A button size, one of the standard bootstrap sizes `BootstrapStyles.Size`.
 * @param outline         If true, selects the outline style for the button. More: Bootstrap Docs.
 * @param block           If true, rendered button will be a full-width block.
 * @param tag             HTML tag used in button, one of tags defined in `ButtonTag`
 * @param customModifiers Sequence of custom modifiers.
 */
final case class UdashButtonOptions(
  color: Opt[BootstrapStyles.Color] = BootstrapStyles.Color.Secondary.opt,
  size: Opt[BootstrapStyles.Size] = Opt.empty,
  outline: Boolean = false,
  block: Boolean = false,
  tag: ButtonTag = ButtonTag.Button,
  customModifiers: Seq[Modifier] = Seq.empty
) extends AbstractCase

final class UdashButton private(
  override val componentId: ComponentId,
  active: ReadableProperty[Boolean],
  disabled: ReadableProperty[Boolean],
  options: UdashButtonOptions
)(content: Binding.NestedInterceptor => Modifier) extends UdashBootstrapComponent with Listenable {

  override type EventType = ButtonClickEvent

  private val classes: Seq[Modifier] =
    Seq(
      BootstrapStyles.Button.btn: Modifier,
      options.color.map(if (options.outline) BootstrapStyles.Button.outline _ else BootstrapStyles.Button.color _): Modifier,
      BootstrapStyles.Button.block.styleIf(options.block),
      nestedInterceptor(BootstrapStyles.active.styleIf(active)),
      nestedInterceptor(BootstrapStyles.disabled.styleIf(disabled)),
      nestedInterceptor(JsDom.all.disabled.attrIf(disabled)),
      seqNodeFromOpt(options.size.map(size => BootstrapStyles.Button.size(size): Modifier))
    ) ++ options.customModifiers


  override val render: dom.html.Element = {
    (options.tag match {
      case ButtonTag.Button =>
        button(componentId, tpe := "button")(classes)(
          onclick :+= ((me: MouseEvent) => if (!disabled.get) fire(ButtonClickEvent(this, me)))
        )
      case ButtonTag.Anchor(url) =>
        a(componentId)(classes)(href := url)
      case ButtonTag.Div =>
        div(componentId)(classes)(
          onclick :+= ((me: MouseEvent) => if (!disabled.get) fire(ButtonClickEvent(this, me)))
        )
    }) (content(nestedInterceptor)).render
  }

  override def kill(): Unit = {
    super.kill()
    jQSelector().button("dispose")
  }

  private def jQSelector(): UdashButtonJQuery =
    jQ(s"#$componentId").asInstanceOf[UdashButtonJQuery]
}

object UdashButton {
  final case class ButtonClickEvent(source: UdashButton, mouseEvent: MouseEvent) extends AbstractCase with ListenableEvent

  /**
   * Holds button enclosing tag options. Since buttons have their own click listeners implemented they can be enclosed
   * in various tags, e.g.:
   *
   * - Button - encloses the button in  tags
   * - Anchor - encloses the button in  tags. For this type of tags link options can be used to indicate the href
   * to redirect user on click
   * - Div    - encloses the button in 
tags */ sealed trait ButtonTag object ButtonTag { final case object Button extends ButtonTag final case class Anchor(href: String) extends ButtonTag final case object Div extends ButtonTag } /** * Creates a button component. * More: Bootstrap Docs. * * @param componentId An id of the root DOM node. * @param active A property indicating if the button is in the `active` state. * @param disabled A property indicating if the button is disabled. * @param options `UdashButton` options object * @param content A content of the button. * Use the provided interceptor to properly clean up bindings inside the content. * @return A `UdashButton` component, call `render` to create a DOM element representing this button. */ def apply( componentId: ComponentId = ComponentId.generate(), active: ReadableProperty[Boolean] = UdashBootstrap.False, disabled: ReadableProperty[Boolean] = UdashBootstrap.False, options: UdashButtonOptions = UdashButtonOptions() )(content: Binding.NestedInterceptor => Modifier): UdashButton = new UdashButton(componentId, active, disabled, options)(content) /** * Creates a toggle button component. * More: Bootstrap Docs. * * @param componentId An id of the root DOM node. * @param active A property indicating if the button is in the `active` state. * @param disabled A property indicating if the button is disabled. * @param options `UdashButton` options object * @param content A content of the button. Use the provided interceptor to properly clean up bindings inside the content. * @return A `UdashButton` component, call `render` to create a DOM element representing this button. */ def toggle( componentId: ComponentId = ComponentId.generate(), active: Property[Boolean], disabled: ReadableProperty[Boolean] = UdashBootstrap.False, options: UdashButtonOptions = UdashButtonOptions() )(content: Binding.NestedInterceptor => Modifier): UdashButton = { val button = new UdashButton(componentId, active, disabled, options)(content) button.listen { case _ => active.set(!active.get) } button } @js.native private trait UdashButtonJQuery extends JQuery { def button(cmd: String): UdashButtonJQuery = js.native } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy