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

scalacss.mutable.StyleSheet.scala Maven / Gradle / Ivy

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

import scalacss._
import DslBase.{DslCond, ToStyle}

/**
 * Mutable StyleSheets provide a context in which many styles can be created using a DSL.
 *
 * They are mutable because they maintain a list of registered styles, meaning you can declare each style one at a time
 * instead of having to create a list of styles in a single expression.
 *
 * Each style itself is immutable.
 */
object StyleSheet {

  /**
   * Classes defined in the REPL appear like this:
   *   $line8.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.MyStyles
   */
  private def fixRepl(s: String): String =
    s.replaceFirst("""^\$line.+[.$]\$iw[.$]""", "")

  abstract class Base {
    protected def register: Register

    protected implicit val classNameHint: ClassNameHint =
      ClassNameHint(
        fixRepl(getClass.getName)
          .replaceFirst("\\$+$", "")
          .replaceFirst("""^(?:.+\.)(.+?)$""", "$1")
          .replaceAll("\\$+", "_"))

    protected object dsl extends DslBase {
      override def styleS(t: ToStyle*)(implicit c: Compose) = Dsl.style(t: _*)

      @inline final def ^ = Literal

      @inline final def Color(literal: String) = scalacss.Color(literal)

      @inline implicit final def toCondOps[C <% Cond](x: C) = new CondOps(x)
      final class CondOps(val cond: Cond) {
        @inline def - = new DslCond(cond, dsl)
      }
    }

    final def css(implicit env: Env): Css =
      register.css

    final def styles: Vector[StyleA] =
      register.styles

    /**
     * Render registered styles into some format, usually a String of plain CSS.
     *
     * @param env The target environment in which the styles are to be used.
     *            Allows customisation of required CSS.
     */
    final def render[Out](implicit r: Renderer[Out], env: Env): Out =
      register.render

    /**
     * Render registered styles into some format, usually a String of plain CSS.
     *
     * The `A` suffix stands for ''absolute'', in that it doesn't perform any environment customisation, and as such
     * an [[Env]] isn't required.
     */
    final def renderA[Out](implicit r: Renderer[Out]): Out =
      render(r, Env.empty)
  }


  /**
   * A standalone stylesheet has the following properties:
   *
   *   - Intent is to generate static CSS for external consumption.
   *   - It is comparable to SCSS/LESS.
   *   - Styles go into a pool of registered styles when they are declared and return `Unit`.
   *   - Style class names / CSS selectors must be provided.
   *   - Only static styles ([[StyleS]]) are usable.
   */
  abstract class Standalone(protected implicit val register: Register) extends Base {
    import dsl._

    @inline protected final implicit class RootStringOps(val sel: CssSelector) extends Pseudo.ChainOps[RootStringOps] {
      override protected def addPseudo(p: Pseudo): RootStringOps =
        new RootStringOps(p modSelector sel)

      /**
       * Create a root style.
       *
       * {{{
       *   "div.stuff" - (
       *     ...
       *   )
       * }}}
       */
      def -(t: ToStyle*)(implicit c: Compose): Unit =
        register registerS styleS(unsafeRoot(sel)(t: _*))
    }

    protected final class NestedStringOps(val sel: CssSelector) extends Pseudo.ChainOps[NestedStringOps] {
      override protected def addPseudo(p: Pseudo): NestedStringOps =
        new NestedStringOps(p modSelector sel)

      /** Create a nested style. */
      def -(t: ToStyle*)(implicit c: Compose): StyleS =
        styleS(unsafeChild(sel)(t: _*))
    }

    @inline final protected def & : Cond = Cond.empty

    /** Create a child style. */
    @inline final protected def &(sel: CssSelector): NestedStringOps = new NestedStringOps(sel)
  }


  /**
   * An inline stylesheet has the following properties:
   *
   *   - Intent is to create styles that can be applied directly to HTML in Scala/Scala.JS.
   *   - Each style is stored in a `val` of type `StyleA`.
   *   - Styles are applied to HTML by setting the `class` attribute of the HTML to the class(es) in a `StyleA`.
   *   - Style class names / CSS selectors are automatically generated.
   *   - All style types ([[StyleS]], [[StyleF]]) are usable.
   */
  abstract class Inline(protected implicit val register: Register) extends Base with Macros.DslMixin {
            final protected type Domain[A] = scalacss.Domain[A]
    @inline final protected def  Domain    = scalacss.Domain

    override protected def __macroStyle    (name: String) = new MStyle (name)
    override protected def __macroStyleF   (name: String) = new MStyleF(name)
    override protected def __macroKeyframes(name: String) = new MKeyframes(name)
    override protected def __macroKeyframe                = new MKStyle
    override protected def __macroFontFace                = new MFontFace

    protected class MStyle(name: String) extends DslMacros.MStyle {
      override def apply(t: ToStyle*)(implicit c: Compose): StyleA = {
        val s1 = Dsl.style(t: _*)
        val s2 = register.applyMacroName(name, s1)
        register registerS s2
      }

      override def apply(className: String)(t: ToStyle*)(implicit c: Compose): StyleA =
        register registerS Dsl.style(className)(t: _*)
    }

    protected class MStyleF(name: String) extends DslMacros.MStyleF {
      override protected def create[I](manualName: Option[String], d: Domain[I], f: I => StyleS, classNameSuffix: (I, Int) => String) =
        manualName match {
          case None    => register.registerFM(StyleF(f)(d), name)(classNameSuffix)
          case Some(n) => register.registerF2(StyleF(f)(d), n)(classNameSuffix)
        }
    }

    protected class MKeyframes(name: String) extends DslMacros.MKeyframes {
      override def apply(frames: (KeyframeSelector, StyleA)*): Keyframes =
        register.registerKeyframes(Keyframes(ClassName(name), frames))
    }

    protected class MKStyle extends DslMacros.MStyle {
      override def apply(t: ToStyle*)(implicit c: Compose): StyleA = {
        val s = Dsl.style(t: _*)
        StyleA(ClassName("keyframe"), s.addClassNames, s)
      }

      override def apply(className: String)(t: ToStyle*)(implicit c: Compose): StyleA =
        apply(t:_*)
    }

    protected class MFontFace extends DslMacros.MFontFace {
      override def apply(fontFamily: String)(config: FontFace.FontSrcSelector => FontFace): FontFace = {
        register.registerFontFace(config(new FontFace.FontSrcSelector(fontFamily)))
      }
    }

    @inline final protected def & : Cond = Cond.empty

    /**
     * Objects in Scala are lazy. If you put styles in inner objects you need to make sure they're initialised before
     * your styles are rendered.
     * To do so, call this at the end of your stylesheet with one style from each inner object.
     */
    protected def initInnerObjects(a: StyleA*) = ()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy