geddski / csstyle

MOVED TO https://github.com/csstyle/csstyle a modern approach for crafting beautifully maintainable stylesheets
http://csstyle.io
Other
851 stars 34 forks source link

Extend a component #38

Closed GesJeremie closed 9 years ago

GesJeremie commented 9 years ago

For my job, i'm creating some base components (button, well, form, etc ...) to have a fresh UI when I start a new project.

For sure I will edit some components to match with the current design of the application I will build.

So I wanted to know how to extend a component (clean way).

// button.sass
@include component(button)
  // ....
// app.sass

// Here I want to "hook", "extends" the component and add new classes
@ ????????

// I didn't try that but maybe it works ?
@include component(button)
  // My hooks here.
emilniklas commented 9 years ago

You could argue that inheritance is redundant since we have options. However I agree with you that this would be nice to have while trying to think CSS in terms of OOP.

In native Sass you can write

@extend .button;

which works as you'd expect.

Unfortunately it doesn't seem to work to pass function returns to the @extend directive, without escaping:

@function component($name) {
    @return #{'.#{$name}'};
}
@extend component(button); // DOES NOT WORK
@extend #{component(button)}; // DOES WORK

Moreover, one could consider maybe a second argument to the component mixin:

@include component(submit, button) {
    //
}

This would of course do the @extend #{$extend} behind the scenes.

Or maybe, if we are focusing on explicit, comfortable syntax, we could have an extends function, which just passes the parent component name to the said second argument:

@include component(submit, extends(button)) {
    //
}

I would love to see an intuitive way to do this while preserving the clear syntax of csstyle.

geddski commented 9 years ago

Thanks @GesJeremie, this is a use case I hadn't thought of. Some good ideas there from @emilniklas. I especially like the explicit extends(parent) idea. Let me play around with a few ideas and get back to you. Happy to hear additional input as well.

geddski commented 9 years ago

Here's one way we could accomplish this:

@mixin inherit($name){
  @extend .#{$name};
}
@include component(fancytweet){
  @include inherit(tweet);
  color: blue;
}
emilniklas commented 9 years ago

Hmm. I wonder what the most commonly used term for this is. I personally like extends more than inherits. But maybe if we're breaking it out from the component mixin, inherit is a more descriptive word.

Reading out "include" before whatever word we choose, for me, is relevant somehow. It seems "include extends" is just as weird as "include inherits". Another option might be "include parent". Hmm...

GesJeremie commented 9 years ago

Maybe that ? (.sass) :

@include component(fancytweet)
  @include use(tweet)
  color: blue

or

@include component(fancytweet)
  @include base(tweet)
  color: blue

or

@include component(fancytweet)
  @include version(tweet)
  color: blue

or

@include component(fancytweet)
  @include _(tweet)
  color: blue
emilniklas commented 9 years ago

Once more we should be clear on when to use this instead of options. In @GesJeremie's example a fancy tweet should be .tweet.--fancy, right?

GesJeremie commented 9 years ago

For me, that stuff is not an option, i don't know how we can do, but for example I finished a button component :

// ===========================================================
// Component Button (v.1.0)
// ===========================================================
//
// UI button component for csstyle.io
//
// Copyright (c) 2015 Ges Jeremie
// http://www.gesjeremie.fr/
// 

// ===========================================================
// Config
// ===========================================================
$csstyle-button-namespace: "button" !default
$csstyle-button-font-family:  "Helvetica Neue", Helvetica, Arial, sans-serif !default
$csstyle-button-font-weight: 300 !default
$csstyle-button-base-font-size: 15px !default
$csstyle-button-base-padding-top-bottom: 6px !default
$csstyle-button-base-padding-right-left: 12px !default

// ===========================================================
// Mixins
// ===========================================================
=csstyle-button-variant($background, $color, $border)
  background-color: $background
  color: $color
  border-color: $border

=csstyle-button-size($font-size, $padding-top-bottom, $padding-right-left)
  font-size: $font-size
  padding: $padding-top-bottom $padding-right-left

// ===========================================================
// Component
// ===========================================================
@include component($csstyle-button-namespace)

  // ===========================================================
  // Default part
  // ===========================================================
  font-family: $csstyle-button-font-family
  font-weight: $csstyle-button-font-weight
  cursor: pointer
  text-decoration: none !important
  -ms-touch-action: manipulation
  touch-action: manipulation
  cursor: pointer
  -webkit-user-select: none
  -moz-user-select: none
  -ms-user-select: none
  user-select: none
  border-radius: 5px
  border: 1px solid transparent
  +csstyle-button-variant(#d6e1e5, #5e696d, #d6e1e5)
  +csstyle-button-size($csstyle-button-base-font-size, $csstyle-button-base-padding-top-bottom, $csstyle-button-base-padding-right-left)

  &:hover,
  &:focus,
  &:active,
    outline: 0
    +csstyle-button-variant(#e1eef3, #5e696d, #e1eef3)

  // ===========================================================
  // Sizes
  // ===========================================================

  // extra small button
  @include option(xs)
    +csstyle-button-size($csstyle-button-base-font-size * 0.8, $csstyle-button-base-padding-top-bottom * 0.6, $csstyle-button-base-padding-right-left * 0.6)

  // small button
  @include option(sm)
    +csstyle-button-size($csstyle-button-base-font-size * 0.8, $csstyle-button-base-padding-top-bottom * 0.8, $csstyle-button-base-padding-right-left * 0.8)

  @include option(md)
    +csstyle-button-size($csstyle-button-base-font-size, $csstyle-button-base-padding-top-bottom, $csstyle-button-base-padding-right-left)

  // large button
  @include option(lg)
    +csstyle-button-size($csstyle-button-base-font-size * 1.2, $csstyle-button-base-padding-top-bottom * 1.2, $csstyle-button-base-padding-right-left * 1.2)

  // extra large button
  @include option(xl)
    +csstyle-button-size($csstyle-button-base-font-size * 1.4, $csstyle-button-base-padding-top-bottom * 1.6, $csstyle-button-base-padding-right-left * 1.6)

  // ===========================================================
  // Block
  // ===========================================================

  @include option(block)
    width: 100%
    display: inline-block

  // ===========================================================
  // Colors
  // ===========================================================

  // Default
  @include option(default)
    +csstyle-button-variant(#d6e1e5, #5e696d, #d6e1e5)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#e1eef3, #5e696d, #e1eef3)

  // Success
  @include option(success)
    +csstyle-button-variant(#3eb5ac, #fff, #3eb5ac)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#45c8be, #fff, #45c8be)

  // Primary
  @include option(primary)
    +csstyle-button-variant(#02baf2, #fff, #02baf2)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#0fc7ff, #fff, #0fc7ff)

  // Info
  @include option(info)
    +csstyle-button-variant(#a88cd5, #fff, #a88cd5)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#b094de, #fff, #b094de)

  // Warning
  @include option(warning)
    +csstyle-button-variant(#f58410, #fff, #f58410)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#ff9324, #fff, #ff9324)

  // Danger
  @include option(danger)
    +csstyle-button-variant(#f84545, #fff, #f84545)

    &:hover,
    &:active,
    &:focus
      +csstyle-button-variant(#ff5f5f, #fff, #ff5f5f)

  // ===========================================================
  // Disabled
  // ===========================================================

  // Disabled
  @include option(disabled)
    pointer-events: none
    cursor: not-allowed
    filter: alpha(opacity=65)
    opacity: .65

  // ===========================================================
  // Icon
  // ===========================================================
  @include option(icon)
    i
      padding-right: 3px

When i will release that code on github, people will get the possibility to download and import the component in their projects via bower.

For sure someone will want to add new colors or new sizes, I imagine something like that :

@include component(mybutton)

  // Here we import all options, part of the base button
  @include clone(button)

  // Now we can add parts or options
  @include option(xxl)
    +csstyle-button-size($csstyle-button-base-font-size * 2, $csstyle-button-base-padding-top-bottom * 1.6, $csstyle-button-base-padding-right-left * 1.8)

Make sense ?

GesJeremie commented 9 years ago

So I just released my first component : http://csstyle-components.github.io/button/, and i'm waiting for other replies for that "issue", I think it's really important.

keyurshah commented 9 years ago

Very interested in this. A system to allow sharing and extending / modifying seems awesome

geddski commented 9 years ago

@GesJeremie I thought of another simple way to accomplish this:

  1. Load the base button styles
  2. Override any component/options/parts etc by simply including the custom styles.

For example, let's say this is your base button definition:

@include component(button){
  background: blue;

  @include option(active){
    background: yellow;
  }
}

You can override any style of this base definition, and even add additional options like so:

@include component(button){

  @include option(warning){
    background: red;
  }

}

Notice that we didn't need to extend or inherit anything. The combined generated output of these files would then be:

.button {
  background: blue; 
}

.button.\--active {
  background: yellow; 
}

.button.\--warning {
  background: red; 
}

What do you think? The only gotcha would be making sure that the base styles are included before the user styles.

geddski commented 9 years ago

PS awesome project you're working on!

GesJeremie commented 9 years ago

@geddski I didn't try that but it make sense. Sounds perfect and already done ahaha :)