scalacss icon indicating copy to clipboard operation
scalacss copied to clipboard

Parent method in conditional CSS

Open malcheg opened this issue 8 years ago • 3 comments

Use case: we need to use button hovers on desktop only, so we can detect desktop devices and add class "no-touch" to html tag. CSS should be:

.no-touch .link:hover {...}

It would be fine, if we had some parent() method for ampersand, e.g.

val link = style(
  ...,
  &.hover.parent(".no-touch")(
    ...
  )
)

malcheg avatar Apr 11 '16 10:04 malcheg

I can't remember if there's a way to do this with the existing DSL or not.

If not, the good news is that it will be trivial to add as the underlying mechanics are already in place to support it. It might just need a PR to wire it up with a prepend value. https://github.com/japgolly/scalacss/blob/master/core/src/main/scala/scalacss/Style.scala#L35-L42

So you'd just want to end up with a value of sel like (".no-touch " + _).

japgolly avatar Apr 14 '16 22:04 japgolly

I wanted this functionality too, and independently re-invented it as an unsafeParent method, very similar to the existing unsafeRoot and unsafeChild methods. I was going to file a new issue, but discovered this one already existed :-)

This is what I came up with, which would be an trivial addition to DslBase:

  /** Enables a parent CSS selector to be added to the style, along the lines of the SASS `parent-selector &` construct.
    *
    * Parent selectors are useful for customizing styles based upon a CSS class added to a parent element (e.g. for language localization, or for browser-specific customization).
    *
    * Use `unsafeParent` like this:
    *
    * {{{
    * val styleWithJaCustomizations = style(
    *   // common styles here ...
    *   unsafeParent(".ja")(
    *     color(pink)
    *   )
    * )
    * }}}
    *
    * This will generate something along the lines of:
    *
    * {{{
    * .Css_Container-styleWithJaCustomizations {
    *   // common styles here ...
    * }
    *
    * .ja .Css_Container-styleWithJaBrowserCustomizations {
    *   color: pink;
    * }
    * }}}
    *
    * @param p The name of the parent CSS selector.
    * @param t The content to be included under the parent selector.
    * @return An [[Style.UnsafeExt]] object that will emit the desired CSS.
    */
  def unsafeParent(p: String)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt = unsafeExt(p + " " + _)(t: _*)

Until this feature is implemented in DslBase (presumably placed next to unsafeChild), end-users may wish to add a trait like the following to their project, and then extend that rather than scalacss.StyleSheet.Inline:

import scalacss.internal.Compose
import scalacss.internal.DslBase.ToStyle

trait AugmentedStylesheetInline extends scalacss.StyleSheet.Inline {
  import dsl._
  def unsafeParent(p: String)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt = unsafeExt(p + " " + _)(t: _*)
}

djneades avatar Aug 23 '17 21:08 djneades

@japgolly What is the status of this? The issue is quite old, perhaps this feature is already implement? If so please point me to the right place. Otherwise, what do you think about including this into the library? I've extended it a bit:

import scalacss.internal.{Compose, StyleA}
import scalacss.internal.DslBase.ToStyle

trait AugmentedStylesheetInline extends scalacss.StyleSheet.Inline {
  import dsl._

    def ancestor(p: StyleA)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt = unsafeParent(s".${p.htmlClass}")(t: _*)

    def parent(p: StyleA)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt = unsafeParent(s".${p.htmlClass} >")(t: _*)

    def unsafeParent(p: String)(t: ToStyle*)(implicit c: Compose): Style.UnsafeExt = unsafeExt(p + " " + _)(t: _*)
}

Named it just parent and ancestor as it will fail at compile if given style (css class) is removed. Or maybe by "safe" you mean something more?

In any case, I can make a PR, unless there is a reason you wouldn't want such change introduced? Cheers

ioleo avatar Jul 04 '20 11:07 ioleo