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

scalacss.package.scala Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
import scalaz.Equal
import scalaz.std.stream.streamEqual
import scalaz.std.option.optionEqual

package object scalacss {
  private[this] implicit def stringEqual: Equal[String] = Equal.equalA

  /**
   * A CSS value, like `"none"`, `"solid 3px black"`.
   */
  type Value = String

  private[scalacss] final val _important = " !important"

  /** Defines the range of unicode characters the font face supports. */
  case class UnicodeRange(from: Int, to: Int) {
    override def toString = "U+%x-%x".format(from, to)
  }

  final case class ClassName(value: String)
  implicit def classNameEquality: Equal[ClassName] = Equal.equalA

  /**
   * Describes the context of a number of CSS attribute-value pairs.
   *
   * Examples: `"div"`, `".debug"`, `"h3.bottom"`, `"a:visited"`.
   */
  type CssSelector = String

  /**
   * A CSS attribute and its corresponding value.
   *
   * Example: `CssKV("margin-bottom", "12px")`
   */
  final case class CssKV(key: String, value: String)
  object CssKV {
    implicit val equality: Equal[CssKV] = Equal.equalA

    final class Lens(val get: CssKV => String, val set: (CssKV, String) => CssKV)
    val key   = new Lens(_.key  , (a, b) => CssKV(b, a.value))
    val value = new Lens(_.value, (a, b) => CssKV(a.key, b))
  }

  /**
   * A media query in CSS.
   *
   * Examples: `"@media screen and (device-aspect-ratio: 16/9)"`.
   */
  type CssMediaQuery  = String
  type CssMediaQueryO = Option[CssMediaQuery]

  /**
   * Keyframe animations in CSS.
   *
   * This is the name of a `@keyframes` group.
   */
  type KeyframeAnimationName = ClassName
  type KeyframeSelector      = Percentage[Int]

  sealed trait CssEntry

  case class CssStyleEntry(mq     : CssMediaQueryO,
                           sel    : CssSelector,
                           content: NonEmptyVector[CssKV]) extends CssEntry

  case class CssKeyframesEntry(name  : KeyframeAnimationName,
                               frames: Map[KeyframeSelector, StyleStream]) extends CssEntry

  case class CssFontFace(fontFamily  : String,
                         src         : NonEmptyVector[String],
                         fontStretch : Option[Value],
                         fontStyle   : Option[Value],
                         fontWeight  : Option[Value],
                         unicodeRange: Option[UnicodeRange]) extends CssEntry

  object CssStyleEntry {
    implicit val equality: Equal[CssStyleEntry] = {
      val A = Equal[CssMediaQueryO]
      val B = Equal[CssSelector]
      val C = Equal[NonEmptyVector[CssKV]]
      new Equal[CssStyleEntry] {
        override val equalIsNatural = A.equalIsNatural
        override def equal(a: CssStyleEntry, b: CssStyleEntry): Boolean =
          B.equal(a.sel, b.sel) &&
          A.equal(a.mq, b.mq) &&
          C.equal(a.content, b.content)
      }
    }
  }

  object CssKeyframesEntry {
    implicit val equality: Equal[CssKeyframesEntry] = {
      val A = Equal[KeyframeAnimationName]
      val B = Equal[StyleStream]
      new Equal[CssKeyframesEntry] {
        override val equalIsNatural = A.equalIsNatural
        override def equal(a: CssKeyframesEntry, b: CssKeyframesEntry): Boolean =
          A.equal(a.name, b.name) &&
          a.frames.size == b.frames.size &&
          a.frames.keys.forall(k => b.frames.get(k).exists(B.equal(a.frames(k), _)))
      }
    }
  }

  object CssFontFace {
    implicit val equality: Equal[CssFontFace] = {
      val A = Equal[String]
      new Equal[CssFontFace] {
        override val equalIsNatural =
          A.equalIsNatural
        override def equal(a: CssFontFace, b: CssFontFace): Boolean =
          A.equal(a.fontFamily, b.fontFamily)
      }
    }
  }

  type StyleStream    = Stream[CssStyleEntry]
  type KeyframeStream = Stream[CssKeyframesEntry]
  type FontFaceStream = Stream[CssFontFace]

  /**
   * A stylesheet in its entirety. Normally turned into a `.css` file or a `<style>` tag.
   */
  type Css = Stream[CssEntry]
  implicit val cssEquality: Equal[Css] = streamEqual(new Equal[CssEntry] {
    override def equal(a1: CssEntry, a2: CssEntry): Boolean = { (a1, a2) match {
      case (a: CssStyleEntry, b: CssStyleEntry) =>
        CssStyleEntry.equality.equal(a, b)
      case (a: CssKeyframesEntry, b: CssKeyframesEntry) =>
        CssKeyframesEntry.equality.equal(a, b)
      case (a: CssFontFace, b: CssFontFace) =>
        CssFontFace.equality.equal(a, b)
      case _ => false
    }}})

  type WarningMsg = String
  final case class Warning(cond: Cond, msg: WarningMsg)

  /**
   * Applicable style.
   *
   * A style that needs no more processing and can be applied to some target.
   *
   * @param addClassNames Additional class names that the style has requested be appended.
   *                      Allows ScalaCSS styles to use classname-based CSS libraries like Bootstrap.
   */
  final case class StyleA(className: ClassName, addClassNames: Vector[ClassName], style: StyleS) {
    def classNameIterator: Iterator[ClassName] =
      Iterator.single(className) ++ addClassNames

    /** Value to be applied to a HTML element's `class` attribute. */
    val htmlClass: String =
      classNameIterator.map(_.value).mkString(" ")

    def +(s : StyleA)(implicit c: Compose): StyleA =
      StyleA(className, s.className +: (addClassNames ++ s.addClassNames), style.compose(s.style))
  }

  /** Faster than Vector(a) */
  @inline private[scalacss] def Vector1[A](a: A): Vector[A] =
    Vector.empty :+ a

  /**
   * Text to include in generated class names.
   *
   * [[mutable.Register.NameGen]]s can choose to include it in the output class names, or ignore it.
   */
  final case class ClassNameHint(value: String)

  /**
    * Animation keyframes.
    *
    * @param name Name of animation.
    * @param frames Frame definitions.
    */
  final case class Keyframes(name: KeyframeAnimationName, frames: Seq[(KeyframeSelector, StyleA)])

  /**
    * Font face declaration
    *
    * http://www.w3schools.com/cssref/css3_pr_font-face_rule.asp
    */
  final case class FontFace(fontFamily         : String,
                            src                : NonEmptyVector[String],
                            fontStretchValue   : Option[Value] = None,
                            fontStyleValue     : Option[Value] = None,
                            fontWeightValue    : Option[Value] = None,
                            unicodeRangeValue  : Option[UnicodeRange] = None) {
    import FontFace._
    def fontStretch                      = new FontStretchBuilder(v => copy(fontStretchValue  = Some(v)))
    def fontStyle                        = new FontStyleBuilder  (v => copy(fontStyleValue    = Some(v)))
    def fontWeight                       = new FontWeightBuilder (v => copy(fontWeightValue   = Some(v)))
    def unicodeRange(from: Int, to: Int) = copy(unicodeRangeValue = Some(UnicodeRange(from, to)))
  }

  object FontFace {
    final class FontSrcSelector(private val fontFamily: String) extends AnyVal {
      def src(src: String, additionalSrc: String*): FontFace =
        FontFace(fontFamily, NonEmptyVector(src, additionalSrc.toVector))
    }

    final class FontStretchBuilder(private val b: Value => FontFace) extends AnyVal {
      @inline def condensed      = b(Literal.condensed)
      @inline def expanded       = b(Literal.expanded)
      @inline def extraCondensed = b(Literal.extraCondensed)
      @inline def extraExpanded  = b(Literal.extraExpanded)
      @inline def normal         = b(Literal.normal)
      @inline def semiCondensed  = b(Literal.semiCondensed)
      @inline def semiExpanded   = b(Literal.semiExpanded)
      @inline def ultraCondensed = b(Literal.ultraCondensed)
      @inline def ultraExpanded  = b(Literal.ultraExpanded)
    }

    final class FontStyleBuilder(private val b: Value => FontFace) extends AnyVal {
      @inline def italic  = b(Literal.italic)
      @inline def normal  = b(Literal.normal)
      @inline def oblique = b(Literal.oblique)
    }

    final class FontWeightBuilder(private val b: Value => FontFace) extends AnyVal {
      @inline def _100    = b("100")
      @inline def _200    = b("200")
      @inline def _300    = b("300")
      @inline def _400    = b("400")
      @inline def _500    = b("500")
      @inline def _600    = b("600")
      @inline def _700    = b("700")
      @inline def _800    = b("800")
      @inline def _900    = b("900")
      @inline def bold    = b(Literal.bold)
      @inline def bolder  = b(Literal.bolder)
      @inline def lighter = b(Literal.lighter)
      @inline def normal  = b(Literal.normal)
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy