// Contains the interpretation of CSS properties, as used by the property optimizer var breakUp = require('./configuration/break-up'); var canOverride = require('./configuration/can-override'); var restore = require('./configuration/restore'); var propertyOptimizers = require('./level-1/property-optimizers'); var valueOptimizers = require('./level-1/value-optimizers'); var override = require('../utils/override'); // Properties to process // Extend this object in order to add support for more properties in the optimizer. // // Each key in this object represents a CSS property and should be an object. // Such an object contains properties that describe how the represented CSS property should be handled. // Possible options: // // * components: array (Only specify for shorthand properties.) // Contains the names of the granular properties this shorthand compacts. // // * canOverride: function // Returns whether two tokens of this property can be merged with each other. // This property has no meaning for shorthands. // // * defaultValue: string // Specifies the default value of the property according to the CSS standard. // For shorthand, this is used when every component is set to its default value, therefore it should be the shortest possible default value of all the components. // // * shortestValue: string // Specifies the shortest possible value the property can possibly have. // (Falls back to defaultValue if unspecified.) // // * breakUp: function (Only specify for shorthand properties.) // Breaks the shorthand up to its components. // // * restore: function (Only specify for shorthand properties.) // Puts the shorthand together from its components. // var configuration = { animation: { canOverride: canOverride.generic.components([ canOverride.generic.time, canOverride.generic.timingFunction, canOverride.generic.time, canOverride.property.animationIterationCount, canOverride.property.animationDirection, canOverride.property.animationFillMode, canOverride.property.animationPlayState, canOverride.property.animationName ]), components: [ 'animation-duration', 'animation-timing-function', 'animation-delay', 'animation-iteration-count', 'animation-direction', 'animation-fill-mode', 'animation-play-state', 'animation-name' ], breakUp: breakUp.multiplex(breakUp.animation), defaultValue: 'none', restore: restore.multiplex(restore.withoutDefaults), shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.textQuotes, valueOptimizers.time, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-delay': { canOverride: canOverride.generic.time, componentOf: [ 'animation' ], defaultValue: '0s', intoMultiplexMode: 'real', valueOptimizers: [ valueOptimizers.time, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-direction': { canOverride: canOverride.property.animationDirection, componentOf: [ 'animation' ], defaultValue: 'normal', intoMultiplexMode: 'real', vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-duration': { canOverride: canOverride.generic.time, componentOf: [ 'animation' ], defaultValue: '0s', intoMultiplexMode: 'real', keepUnlessDefault: 'animation-delay', valueOptimizers: [ valueOptimizers.time, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-fill-mode': { canOverride: canOverride.property.animationFillMode, componentOf: [ 'animation' ], defaultValue: 'none', intoMultiplexMode: 'real', vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-iteration-count': { canOverride: canOverride.property.animationIterationCount, componentOf: [ 'animation' ], defaultValue: '1', intoMultiplexMode: 'real', vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-name': { canOverride: canOverride.property.animationName, componentOf: [ 'animation' ], defaultValue: 'none', intoMultiplexMode: 'real', valueOptimizers: [ valueOptimizers.textQuotes ], vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-play-state': { canOverride: canOverride.property.animationPlayState, componentOf: [ 'animation' ], defaultValue: 'running', intoMultiplexMode: 'real', vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, 'animation-timing-function': { canOverride: canOverride.generic.timingFunction, componentOf: [ 'animation' ], defaultValue: 'ease', intoMultiplexMode: 'real', vendorPrefixes: [ '-moz-', '-o-', '-webkit-' ] }, background: { canOverride: canOverride.generic.components([ canOverride.generic.image, canOverride.property.backgroundPosition, canOverride.property.backgroundSize, canOverride.property.backgroundRepeat, canOverride.property.backgroundAttachment, canOverride.property.backgroundOrigin, canOverride.property.backgroundClip, canOverride.generic.color ]), components: [ 'background-image', 'background-position', 'background-size', 'background-repeat', 'background-attachment', 'background-origin', 'background-clip', 'background-color' ], breakUp: breakUp.multiplex(breakUp.background), defaultValue: '0 0', propertyOptimizer: propertyOptimizers.background, restore: restore.multiplex(restore.background), shortestValue: '0', shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.urlWhiteSpace, valueOptimizers.fraction, valueOptimizers.zero, valueOptimizers.color, valueOptimizers.urlPrefix, valueOptimizers.urlQuotes ] }, 'background-attachment': { canOverride: canOverride.property.backgroundAttachment, componentOf: [ 'background' ], defaultValue: 'scroll', intoMultiplexMode: 'real' }, 'background-clip': { canOverride: canOverride.property.backgroundClip, componentOf: [ 'background' ], defaultValue: 'border-box', intoMultiplexMode: 'real', shortestValue: 'border-box' }, 'background-color': { canOverride: canOverride.generic.color, componentOf: [ 'background' ], defaultValue: 'transparent', intoMultiplexMode: 'real', // otherwise real color will turn into default since color appears in last multiplex only multiplexLastOnly: true, nonMergeableValue: 'none', shortestValue: 'red', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'background-image': { canOverride: canOverride.generic.image, componentOf: [ 'background' ], defaultValue: 'none', intoMultiplexMode: 'default', valueOptimizers: [ valueOptimizers.urlWhiteSpace, valueOptimizers.urlPrefix, valueOptimizers.urlQuotes, valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero, valueOptimizers.color ] }, 'background-origin': { canOverride: canOverride.property.backgroundOrigin, componentOf: [ 'background' ], defaultValue: 'padding-box', intoMultiplexMode: 'real', shortestValue: 'border-box' }, 'background-position': { canOverride: canOverride.property.backgroundPosition, componentOf: [ 'background' ], defaultValue: ['0', '0'], doubleValues: true, intoMultiplexMode: 'real', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'background-repeat': { canOverride: canOverride.property.backgroundRepeat, componentOf: [ 'background' ], defaultValue: ['repeat'], doubleValues: true, intoMultiplexMode: 'real' }, 'background-size': { canOverride: canOverride.property.backgroundSize, componentOf: [ 'background' ], defaultValue: ['auto'], doubleValues: true, intoMultiplexMode: 'real', shortestValue: '0 0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, bottom: { canOverride: canOverride.property.bottom, defaultValue: 'auto', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, border: { breakUp: breakUp.border, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.property.borderStyle, canOverride.generic.color ]), components: [ 'border-width', 'border-style', 'border-color' ], defaultValue: 'none', overridesShorthands: [ 'border-bottom', 'border-left', 'border-right', 'border-top' ], restore: restore.withoutDefaults, shorthand: true, shorthandComponents: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.zero, valueOptimizers.color ] }, 'border-bottom': { breakUp: breakUp.border, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.property.borderStyle, canOverride.generic.color ]), components: [ 'border-bottom-width', 'border-bottom-style', 'border-bottom-color' ], defaultValue: 'none', restore: restore.withoutDefaults, shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.zero, valueOptimizers.color ] }, 'border-bottom-color': { canOverride: canOverride.generic.color, componentOf: [ 'border-bottom', 'border-color' ], defaultValue: 'none', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-bottom-left-radius': { canOverride: canOverride.generic.unit, componentOf: [ 'border-radius' ], defaultValue: '0', propertyOptimizer: propertyOptimizers.borderRadius, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-' ] }, 'border-bottom-right-radius': { canOverride: canOverride.generic.unit, componentOf: [ 'border-radius' ], defaultValue: '0', propertyOptimizer: propertyOptimizers.borderRadius, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-' ] }, 'border-bottom-style': { canOverride: canOverride.property.borderStyle, componentOf: [ 'border-bottom', 'border-style' ], defaultValue: 'none' }, 'border-bottom-width': { canOverride: canOverride.generic.unit, componentOf: [ 'border-bottom', 'border-width' ], defaultValue: 'medium', oppositeTo: 'border-top-width', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'border-collapse': { canOverride: canOverride.property.borderCollapse, defaultValue: 'separate' }, 'border-color': { breakUp: breakUp.fourValues, canOverride: canOverride.generic.components([ canOverride.generic.color, canOverride.generic.color, canOverride.generic.color, canOverride.generic.color ]), componentOf: [ 'border' ], components: [ 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color' ], defaultValue: 'none', restore: restore.fourValues, shortestValue: 'red', shorthand: true, singleTypeComponents: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-left': { breakUp: breakUp.border, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.property.borderStyle, canOverride.generic.color ]), components: [ 'border-left-width', 'border-left-style', 'border-left-color' ], defaultValue: 'none', restore: restore.withoutDefaults, shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.zero, valueOptimizers.color ] }, 'border-left-color': { canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-left' ], defaultValue: 'none', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-left-style': { canOverride: canOverride.property.borderStyle, componentOf: [ 'border-left', 'border-style' ], defaultValue: 'none' }, 'border-left-width': { canOverride: canOverride.generic.unit, componentOf: [ 'border-left', 'border-width' ], defaultValue: 'medium', oppositeTo: 'border-right-width', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'border-radius': { breakUp: breakUp.borderRadius, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.generic.unit, canOverride.generic.unit, canOverride.generic.unit ]), components: [ 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius' ], defaultValue: '0', propertyOptimizer: propertyOptimizers.borderRadius, restore: restore.borderRadius, shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-' ] }, 'border-right': { breakUp: breakUp.border, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.property.borderStyle, canOverride.generic.color ]), components: [ 'border-right-width', 'border-right-style', 'border-right-color' ], defaultValue: 'none', restore: restore.withoutDefaults, shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-right-color': { canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-right' ], defaultValue: 'none', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-right-style': { canOverride: canOverride.property.borderStyle, componentOf: [ 'border-right', 'border-style' ], defaultValue: 'none' }, 'border-right-width': { canOverride: canOverride.generic.unit, componentOf: [ 'border-right', 'border-width' ], defaultValue: 'medium', oppositeTo: 'border-left-width', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'border-style': { breakUp: breakUp.fourValues, canOverride: canOverride.generic.components([ canOverride.property.borderStyle, canOverride.property.borderStyle, canOverride.property.borderStyle, canOverride.property.borderStyle ]), componentOf: [ 'border' ], components: [ 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style' ], defaultValue: 'none', restore: restore.fourValues, shorthand: true, singleTypeComponents: true }, 'border-top': { breakUp: breakUp.border, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.property.borderStyle, canOverride.generic.color ]), components: [ 'border-top-width', 'border-top-style', 'border-top-color' ], defaultValue: 'none', restore: restore.withoutDefaults, shorthand: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.zero, valueOptimizers.color, valueOptimizers.unit ] }, 'border-top-color': { canOverride: canOverride.generic.color, componentOf: [ 'border-color', 'border-top' ], defaultValue: 'none', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'border-top-left-radius': { canOverride: canOverride.generic.unit, componentOf: [ 'border-radius' ], defaultValue: '0', propertyOptimizer: propertyOptimizers.borderRadius, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-' ] }, 'border-top-right-radius': { canOverride: canOverride.generic.unit, componentOf: [ 'border-radius' ], defaultValue: '0', propertyOptimizer: propertyOptimizers.borderRadius, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ], vendorPrefixes: [ '-moz-', '-o-' ] }, 'border-top-style': { canOverride: canOverride.property.borderStyle, componentOf: [ 'border-style', 'border-top' ], defaultValue: 'none' }, 'border-top-width': { canOverride: canOverride.generic.unit, componentOf: [ 'border-top', 'border-width' ], defaultValue: 'medium', oppositeTo: 'border-bottom-width', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'border-width': { breakUp: breakUp.fourValues, canOverride: canOverride.generic.components([ canOverride.generic.unit, canOverride.generic.unit, canOverride.generic.unit, canOverride.generic.unit ]), componentOf: [ 'border' ], components: [ 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width' ], defaultValue: 'medium', restore: restore.fourValues, shortestValue: '0', shorthand: true, singleTypeComponents: true, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'box-shadow': { propertyOptimizer: propertyOptimizers.boxShadow, valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero, valueOptimizers.color ], vendorPrefixes: [ '-moz-', '-ms-', '-o-', '-webkit-' ] }, clear: { canOverride: canOverride.property.clear, defaultValue: 'none' }, clip: { valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, color: { canOverride: canOverride.generic.color, defaultValue: 'transparent', shortestValue: 'red', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.color ] }, 'column-gap': { valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, cursor: { canOverride: canOverride.property.cursor, defaultValue: 'auto' }, display: { canOverride: canOverride.property.display }, filter: { propertyOptimizer: propertyOptimizers.filter, valueOptimizers: [ valueOptimizers.fraction ] }, float: { canOverride: canOverride.property.float, defaultValue: 'none' }, font: { breakUp: breakUp.font, canOverride: canOverride.generic.components([ canOverride.property.fontStyle, canOverride.property.fontVariant, canOverride.property.fontWeight, canOverride.property.fontStretch, canOverride.generic.unit, canOverride.generic.unit, canOverride.property.fontFamily ]), components: [ 'font-style', 'font-variant', 'font-weight', 'font-stretch', 'font-size', 'line-height', 'font-family' ], restore: restore.font, shorthand: true, valueOptimizers: [ valueOptimizers.textQuotes ] }, 'font-family': { canOverride: canOverride.property.fontFamily, defaultValue: 'user|agent|specific', valueOptimizers: [ valueOptimizers.textQuotes ] }, 'font-size': { canOverride: canOverride.generic.unit, defaultValue: 'medium', shortestValue: '0', valueOptimizers: [ valueOptimizers.fraction ] }, 'font-stretch': { canOverride: canOverride.property.fontStretch, defaultValue: 'normal' }, 'font-style': { canOverride: canOverride.property.fontStyle, defaultValue: 'normal' }, 'font-variant': { canOverride: canOverride.property.fontVariant, defaultValue: 'normal' }, 'font-weight': { canOverride: canOverride.property.fontWeight, defaultValue: 'normal', propertyOptimizer: propertyOptimizers.fontWeight, shortestValue: '400' }, gap: { valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, height: { canOverride: canOverride.generic.unit, defaultValue: 'auto', shortestValue: '0', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, left: { canOverride: canOverride.property.left, defaultValue: 'auto', valueOptimizers: [ valueOptimizers.whiteSpace, valueOptimizers.fraction, valueOptimizers.precision, valueOptimizers.unit, valueOptimizers.zero ] }, 'letter-spacing': { valueOptimizers: [ valueOptimizers.fraction, valueOptimizers.zero ] }, 'line-height': { canOverride: canOverride.generic.unitOrNumber, defaultValue: 'normal', shortestValue: '0', valueOptimizers: [ valueOptimizers.fraction, valueOptimizers.zero ] }, 'list-style': { canOverride: canOverride.generic.components([ canOverride.property.listStyleType, canOverride.property.listStylePosition, canOverride.property.listStyleImage ]), components: [ 'list-style-type', 'list-style-position', 'list-style-image' ], breakUp: breakUp.listStyle, restore: restore.withoutDefaults, defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for