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

scalacss.Dsl.scala Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
package scalacss

import scalaz.{\/, -\/, \/-}
import Style.{UnsafeExt, UnsafeExts}
import ValueT._

object DslBase {
  import Media.{Resolution => _, _}

  // media.
  object MediaQueryEmpty extends TypeAOps[Query] with FeatureOps[Query] {
    override protected def F = f => new Query(\/-(f), Vector.empty)
    override protected def T = t => new Query(-\/(Just(t)), Vector.empty)
    def not  = new MediaQueryNeedType(Not)
    def only = new MediaQueryNeedType(Only)
  }

  // media.{not,only}
  final class MediaQueryNeedType(f: TypeA => TypeExpr) extends TypeAOps[Query] {
    override protected def T = t => new Query(-\/(f(t)), Vector.empty)
  }

  final class DslInt(val self: Int) extends AnyVal {
    def :/:(y: Int) = Ratio(self, y)
  }

  final class DslNum[N](val self: N) extends AnyVal {
    @inline private def mkUnit(u: LengthUnit): Length[N] =
      Length(self, u)

    /** Centimeters. */
    @inline def cm = mkUnit(LengthUnit.cm)

    /**
     * This unit represents the width, or more precisely the advance measure, of the glyph '0' (zero, the Unicode
     * character U+0030) in the element's font.
     */
    @inline def ch = mkUnit(LengthUnit.ch)

    /**
     * This unit represents the calculated font-size of the element.
     * If used on the `font-size` property itself, it represents the inherited `font-size` of the element.
     */
    @inline def em = mkUnit(LengthUnit.em)

    /**
     * This unit represents the x-height of the element's font.
     * On fonts with the 'x' letter, this is generally the height of lowercase letters in the font;
     * 1ex ≈ 0.5em in many fonts.
     */
    @inline def ex = mkUnit(LengthUnit.ex)

    /** Inches (1in = 2.54 cm). */
    @inline def in = mkUnit(LengthUnit.in)

    /** Millimeters. */
    @inline def mm = mkUnit(LengthUnit.mm)

    /** Picas (1pc = 12pt). */
    @inline def pc = mkUnit(LengthUnit.pc)

    /** Points (1pt = 1/72 of 1in). */
    @inline def pt = mkUnit(LengthUnit.pt)

    /**
     * Pixel. Relative to the viewing device.
     * For screen display, typically one device pixel (dot) of the display.
     * For printers and very high resolution screens one CSS pixel implies multiple device pixels, so that the number
     * of pixel per inch stays around 96.
     */
    @inline def px = mkUnit(LengthUnit.px)

    /**
     * This unit represents the `font-size` of the root element (e.g. the `font-size` of the `<html>` element).
     * When used on the `font-size` on this root element, it represents its initial value.
     */
    @inline def rem = mkUnit(LengthUnit.rem)

    /** 1/100th of the height of the viewport. */
    @inline def vh = mkUnit(LengthUnit.vh)

    /** 1/100th of the minimum value between the height and the width of the viewport. */
    @inline def vmin = mkUnit(LengthUnit.vmin)

    /** 1/100th of the maximum value between the height and the width of the viewport. */
    @inline def vmax = mkUnit(LengthUnit.vmax)

    /** 1/100th of the width of the viewport. */
    @inline def vw = mkUnit(LengthUnit.vw)

    /** Size as a percentage. */
    @inline def %% = Percentage(self)

    /** Dots per inch */
    @inline def dpi  = Resolution(self, ResolutionUnit.dpi)

    /** Dots per centimeter */
    @inline def dpcm = Resolution(self, ResolutionUnit.dpcm)

    /**
     * This unit represents the number of dots per px unit. Due to the 1:96 fixed ratio of CSS in to CSS px, 1dppx is
     * equivalent to 96dpi, that corresponds to the default resolution of images displayed in CSS as defined by
     * image-resolution.
     */
    @inline def dppx = Resolution(self, ResolutionUnit.dppx)

    @inline def *(l: Length[N])    (implicit N: Numeric[N]) = l * self
    @inline def *(l: Resolution[N])(implicit N: Numeric[N]) = l * self
  }

  //final class DslStr(val self: String) extends AnyVal {
  //}

  /** Untyped attributes */
  final class DslAttr(val self: Attr) extends AnyVal {
    @inline def :=(value: Value)    : AV = AV(self, value)
    @inline def :=(value: ValueT[_]): AV = AV(self, value.value)
    @inline def :=(value: Literal)  : AV = AV(self, value.value)
  }

  /** Typed attributes */
  final class DslAttrT(val self: TypedAttrBase) extends AnyVal {
    @inline def :=!(value: Value)    : AV = AV(self, value)
    @inline def :=!(value: ValueT[_]): AV = AV(self, value.value)
    @inline def :=!(value: Literal)  : AV = AV(self, value.value)

    @deprecated("Using := bypasses the type-safety of a typed attribute. Use the attribute's methods for type-safety, or :=! to bypass without warning.","always")
    @inline def :=(value: Value)    : AV = AV(self, value)
    @deprecated("Using := bypasses the type-safety of a typed attribute. Use the attribute's methods for type-safety, or :=! to bypass without warning.","always")
    @inline def :=(value: ValueT[_]): AV = AV(self, value.value)
    @deprecated("Using := bypasses the type-safety of a typed attribute. Use the attribute's methods for type-safety, or :=! to bypass without warning.","always")
    @inline def :=(value: Literal)  : AV = AV(self, value.value)
  }

  final class DslAV(val self: AV) extends AnyVal {
    @inline def &(b: AV) : AVs = AVs(self) + b
    @inline def &(b: AVs): AVs = self +: b
  }

  final class DslAVs(val self: AVs) extends AnyVal {
    @inline def &(b: AV) : AVs = self + b
    @inline def &(b: AVs): AVs = self ++ b
  }

  final class DslCond(c: Cond, b: DslBase) {
    @inline def apply(t: ToStyle*)(implicit u: Compose): StyleS = c applyToStyle b.mixin(t: _*)
  }

  final class ToStyle(val s: StyleS) extends AnyVal
}

import DslBase._

// =====================================================================================================================
abstract class DslBase
  extends AttrAliasesAndValueTRules
     with TypedLiteralAliases
     with ColorOps[ValueT[Color]] {

  @inline override protected final def mkColor(s: String) = Color(s)

  @inline implicit final def autoDslInt  (a: Int)          : DslInt         = new DslInt(a)
  @inline implicit final def autoDslNumI (a: Int)          : DslNum[Int]    = new DslNum[Int](a)
  @inline implicit final def autoDslNumD (a: Double)       : DslNum[Double] = new DslNum[Double](a)
  //nline implicit final def autoDslStr  (a: String)       : DslStr         = new DslStr(a)
  @inline implicit final def autoDslAttr (a: Attr)         : DslAttr        = new DslAttr(a)
  @inline implicit final def autoDslAttrT(a: TypedAttrBase): DslAttrT       = new DslAttrT(a)
  @inline implicit final def autoDslAV   (a: AV)           : DslAV          = new DslAV(a)
  @inline implicit final def autoDslAVs  (a: AVs)          : DslAVs         = new DslAVs(a)

  @inline implicit final def DslCond[C <% Cond](x: C): DslCond = new DslCond(x, this)

  @inline implicit final def ToAVToAV(x: ToAV): AV = x.av

  @inline implicit final def CondPseudo    (x: Pseudo)     : Cond = Cond(Some(x), Vector.empty)
  @inline implicit final def CondMediaQuery(x: Media.Query): Cond = Cond(None, Vector1(x))

  @inline implicit final def ToStyleToAV           (x: ToAV)      : ToStyle = ToStyleAV(x.av)
  @inline implicit final def ToStyleAV             (x: AV)        : ToStyle = ToStyleAVs(AVs(x))
          implicit final def ToStyleAVs            (x: AVs)       : ToStyle = new ToStyle(StyleS.data1(Cond.empty, x))
          implicit final def ToStyleCAV [C <% Cond](x: (C, AV))   : ToStyle = new ToStyle(StyleS.data1(x._1, AVs(x._2)))
          implicit final def ToStyleCAVs[C <% Cond](x: (C, AVs))  : ToStyle = new ToStyle(StyleS.data1(x._1, x._2))
  @inline implicit final def ToStyleUnsafeExt      (x: UnsafeExt) : ToStyle = ToStyleUnsafeExts(Vector1(x))
          implicit final def ToStyleUnsafeExts     (x: UnsafeExts): ToStyle = new ToStyle(StyleS.empty.copy(unsafeExts = x))
  @inline implicit final def ToStyleStyleS         (x: StyleS)    : ToStyle = new ToStyle(x)
  @inline implicit final def ToStyleStyleA         (x: StyleA)    : ToStyle = new ToStyle(x.style)

  protected def styleS(t: ToStyle*)(implicit c: Compose): StyleS

  def addClassName(cn: String): StyleS =
    StyleS.empty.copy(addClassNames = Vector1(ClassName(cn)))

  def addClassNames(cn: String*): StyleS =
    StyleS.empty.copy(addClassNames = cn.foldLeft(Vector.empty[ClassName])(_ :+ ClassName(_)))

  def media = MediaQueryEmpty

  def unsafeExt(f: String => String)(t: ToStyle*)(implicit c: Compose): UnsafeExt =
    UnsafeExt(f, Cond.empty, styleS(t: _*))

  def unsafeChild(n: String)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt =
    unsafeExt(_ + " " + n)(t: _*)

  def unsafeRoot(sel: String)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt =
    unsafeExt(_ => sel)(t: _*)

  @inline def mixin(t: ToStyle*)(implicit c: Compose) =
    styleS(t: _*)(c)

  @inline def mixinIf(b: Boolean)(t: ToStyle*)(implicit c: Compose): StyleS =
    if (b) styleS(t: _*)(c) else StyleS.empty

  @inline def mixinIfElse(b: Boolean)(t: ToStyle*)(f: ToStyle*)(implicit c: Compose): StyleS =
    styleS((if (b) t else f): _*)(c)

  @inline implicit def colourLiteralMacro(sc: StringContext) =
    new Macros.ColourLiteral(sc)
}

// =====================================================================================================================
object DslMacros {

  trait MStyle {
    def apply                   (t: ToStyle*)(implicit c: Compose): StyleA
    def apply(className: String)(t: ToStyle*)(implicit c: Compose): StyleA
  }

  trait MStyleF2 {
    protected def create[I](manualName: Option[String], d: Domain[I], f: I => StyleS, classNameSuffix: (I, Int) => String): I => StyleA

    final def bool(f: Boolean => StyleS): Boolean => StyleA =
      create(None, Domain.boolean, f, defaultStyleFClassNameSuffixB)

    final def int(r: Range)(f: Int => StyleS): Int => StyleA =
      create(None, Domain ofRange r, f, defaultStyleFClassNameSuffixI)
  }

  trait MStyleF extends MStyleF2 {

    /** Manually specify a name */
    final def apply(name: String): MStyleF2 =
      new MStyleF2 {
        override protected def create[I](u: Option[String], d: Domain[I], f: I => StyleS, classNameSuffix: (I, Int) => String) =
          MStyleF.this.create(Some(name), d, f, classNameSuffix)
      }

    final def apply[I](d: Domain[I])(f: I => StyleS, classNameSuffix: (I, Int) => String = defaultStyleFClassNameSuffix): I => StyleA =
      create(None, d, f, classNameSuffix)
  }

  trait MKeyframes {
    def apply(frames: (Percentage[Int], StyleA)*): Keyframes
  }

  trait MFontFace {
    def apply(fontFamily: String)(config: FontFace.FontSrcSelector => FontFace): FontFace
  }

  val defaultStyleFClassNameSuffix: (Any, Int) => String =
    (_, index) => (index + 1).toString

  val defaultStyleFClassNameSuffixB: (Boolean, Int) => String =
    (b, _) => if (b) "t" else "f"

  val defaultStyleFClassNameSuffixI: (Int, Int) => String =
    (i, _) => i.toString
}

// =====================================================================================================================
object Dsl extends DslBase {

  override protected def styleS(t: ToStyle*)(implicit c: Compose) =
    style(t: _*)

  def style(className: String)(t: ToStyle*)(implicit c: Compose): StyleS =
    style(t: _*).copy(className = Option(className) map ClassName)

  def style(t: ToStyle*)(implicit c: Compose): StyleS =
    if (t.isEmpty) StyleS.empty
    else t.map(_.s).reduce(_ compose _)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy