unify / unify

Unify Project
http://www.unifyjs.com
Other
152 stars 16 forks source link

Reworked theming #145

Closed stefankolb closed 11 years ago

stefankolb commented 11 years ago

Instead of having a tree-like structure for includes and styles for each appearance selector, there is now a flat list for each appearance selector. This makes extending and overwriting of style definitions much easier and much more reliable, because this way, we can make sure, that styles are applied in the correct order (meaning: First the styles from the root theme and then all styles from all derived themes, if there are any).

Additional Features (some already introduced in earlier commits)

Note Whenever a style is requested, the style is resolved in the following order (see examples below for details about includes and style functions):

  1. All includes are processed recursively (i.e. if the included style has one or several includes, they are processed, too)
  2. All style functions are executed

    Examples

    Single theme

Let's say we have a single theme called 'Base' with the following style definitions:

// ...
'button': {
  style: function(states) {     // function1
    return {
      borderColor: 'black',
      borderRadius: '3px',
      broderStyle: 'solid',
      borderWidth: '1px',
    }
  }
},

'button.blue': {
  include: 'button',
  style: function(states) {   // function2
    return {
      backgroundColor: 'blue',
      borderColor: 'blue'
    }
  }
}
// ...

After the theme was parsed, we end up with a style definition like this:

// ...
'button': [
  {
    theme: 'Base', 
    key: 'button',
    includes: [ ],
    styles: [ function1 ]
  }
],
'button.blue': [
  {
    theme: 'Base', 
    key: 'button.blue',
    includes: [ 'button' ],
    styles: [ function2 ]
  }
],
//...

Multiple themes

Let's say, we have a theme called 'Derived', which includes the 'Base' theme from above. In that theme, we have, among others, the following style definitions:

// ...
'button.blue': {
  include: 'button',
  style: function(states) {   // function3
    return {
      backgroundColor: 'darkblue',
      borderColor: 'darkblue'
    }
  }
},

'button.blue.shadow': {
  include: 'button.blue',
  style: function(states) {   // function4
    return {
      boxShadow: '1px 2px 2px black'
    }
  }
}

// ...

After the theme was parsed, we end up with a style definition like this:

// ...
'button.blue': [
  {
    theme: 'Derived', 
    key: 'button.blue',
    includes: [ 'button' ],
    styles: [ function2, function3 ]
  }
],
'button.blue.shadow': [
  {
    theme: 'Derived', 
    key: 'button.blue.shadow',
    includes: [ 'button.blue' ],
    styles: [ function4 ]
  }
],
//...

The style definition for 'button.blue' in the 'Derived' theme would override the style definition for 'button.blue' in the 'Base' theme.

Clear previous styles

Let's say you want to remove any previously applied styles, e.g. those from a base theme. You just need to provide an empty object for that.

// Base theme
'button': {
  style: function(states) {
    return {
      borderColor: 'black',
      borderRadius: '3px',
      broderStyle: 'solid',
      borderWidth: '1px',
    }
  }
}

// Derived theme
'button': { }   // <- would remove any styling previously applied