@@ -133,13 +133,10 @@ function detectDisabledThemes($mdThemingProvider) {
133133 * {{primary-color-0.7}} - Apply 0.7 opacity to each of the above rules
134134 * {{primary-contrast}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured contrast (ie. text) color shades set for each hue
135135 * {{primary-contrast-0.7}} - Apply 0.7 opacity to each of the above rules
136+ * {{primary-contrast-divider}} - Apply divider opacity to contrast color
137+ * {{background-default-contrast}} - Apply primary text color for contrasting with default background
138+ * {{background-50-contrast-icon}} - Apply contrast color for icon on background's shade 50 hue
136139 *
137- * Foreground expansion: Applies rgba to black/white foreground text
138- *
139- * {{foreground-1}} - used for primary text
140- * {{foreground-2}} - used for secondary text/divider
141- * {{foreground-3}} - used for disabled text
142- * {{foreground-4}} - used for dividers
143140 */
144141
145142// In memory generated CSS rules; registered by theme.name
@@ -148,21 +145,14 @@ var GENERATED = { };
148145// In memory storage of defined themes and color palettes (both loaded by CSS, and user specified)
149146var PALETTES ;
150147
151- // Text Colors on light and dark backgrounds
148+ // Text colors are automatically generated based on background color when not specified
149+ // Custom palettes can provide override colors
152150// @see https://material.io/archive/guidelines/style/color.html#color-usability
153151var DARK_FOREGROUND = {
154152 name : 'dark' ,
155- '1' : 'rgba(0,0,0,0.87)' ,
156- '2' : 'rgba(0,0,0,0.54)' ,
157- '3' : 'rgba(0,0,0,0.38)' ,
158- '4' : 'rgba(0,0,0,0.12)'
159153} ;
160154var LIGHT_FOREGROUND = {
161155 name : 'light' ,
162- '1' : 'rgba(255,255,255,1.0)' ,
163- '2' : 'rgba(255,255,255,0.7)' ,
164- '3' : 'rgba(255,255,255,0.5)' ,
165- '4' : 'rgba(255,255,255,0.12)'
166156} ;
167157
168158var DARK_SHADOW = '1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)' ;
@@ -199,6 +189,34 @@ var DARK_DEFAULT_HUES = {
199189 'hue-3' : 'A200'
200190 }
201191} ;
192+
193+ // use inactive icon opacity from https://material.google.com/style/color.html#color-text-background-colors
194+ // not inactive icon opacity from https://material.google.com/style/icons.html#icons-system-icons
195+
196+ var DARK_CONTRAST_OPACITY = {
197+ 'icon' : 0.54 ,
198+ 'secondary' : 0.54 ,
199+ 'disabled' : 0.38 ,
200+ 'hint' : 0.38 ,
201+ 'divider' : 0.12 ,
202+ } ;
203+
204+ var LIGHT_CONTRAST_OPACITY = {
205+ 'icon' : 0.87 ,
206+ 'secondary' : 0.7 ,
207+ 'disabled' : 0.5 ,
208+ 'hint' : 0.5 ,
209+ 'divider' : 0.12
210+ } ;
211+
212+ var STRONG_LIGHT_CONTRAST_OPACITY = {
213+ 'icon' : 1.0 ,
214+ 'secondary' : 0.7 ,
215+ 'disabled' : 0.5 ,
216+ 'hint' : 0.5 ,
217+ 'divider' : 0.12
218+ } ;
219+
202220THEME_COLOR_TYPES . forEach ( function ( colorType ) {
203221 // Color types with unspecified default hues will use these default hue values
204222 var defaultDefaultHues = {
@@ -974,18 +992,45 @@ function parseRules(theme, colorType, rules) {
974992
975993 rules = rules . replace ( / T H E M E _ N A M E / g, theme . name ) ;
976994 var themeNameRegex = new RegExp ( '\\.md-' + theme . name + '-theme' , 'g' ) ;
977- var simpleVariableRegex = / ' ? " ? \{ \{ \s * ( [ a - z A - Z ] + ) - ( A ? \d + | h u e - [ 0 - 3 ] | s h a d o w | d e f a u l t ) - ? ( \d \. ? \d * ) ? ( c o n t r a s t ) ? \s * \} \} ' ? " ? / g;
995+ // Matches '{{ primary-color }}', etc
996+ var hueRegex = new RegExp ( '(?:\'|")?{{\\s*(' + colorType + ')-?(color|default)?-?(contrast)?-?((?:\\d\\.?\\d*)|(?:[a-zA-Z]+))?\\s*}}(\"|\')?' , 'g' ) ;
997+ var simpleVariableRegex = / ' ? " ? \{ \{ \s * ( [ a - z A - Z ] + ) - ( A ? \d + | h u e - [ 0 - 3 ] | s h a d o w | d e f a u l t ) - ? ( c o n t r a s t ) ? - ? ( (?: \d \. ? \d * ) | (?: [ a - z A - Z ] + ) ) ? \s * \} \} ' ? " ? / g;
998+ var palette = PALETTES [ color . name ] ;
999+ var defaultBgHue = theme . colors [ 'background' ] . hues [ 'default' ] ;
1000+ var defaultBgContrastType = PALETTES [ theme . colors [ 'background' ] . name ] [ defaultBgHue ] . contrastType ;
9781001
9791002 // find and replace simple variables where we use a specific hue, not an entire palette
9801003 // eg. "{{primary-100}}"
9811004 // \(' + THEME_COLOR_TYPES.join('\|') + '\)'
982- rules = rules . replace ( simpleVariableRegex , function ( match , colorType , hue , opacity , contrast ) {
1005+ rules = rules . replace ( simpleVariableRegex , function ( match , colorType , hue , contrast , opacity ) {
1006+ var regexColorType = colorType ;
9831007 if ( colorType === 'foreground' ) {
9841008 if ( hue == 'shadow' ) {
9851009 return theme . foregroundShadow ;
986- } else {
987- return theme . foregroundPalette [ hue ] || theme . foregroundPalette [ '1' ] ;
1010+ } else if ( theme . foregroundPalette [ hue ] ) {
1011+ // Use user defined palette number (ie: foreground-2)
1012+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ hue ] ) ) ;
1013+ } else if ( theme . foregroundPalette [ '1' ] ) {
1014+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ '1' ] ) ) ;
1015+ }
1016+ // Default to background-default-contrast-{opacity}
1017+ colorType = 'background' ;
1018+ contrast = 'contrast' ;
1019+ if ( ! opacity && hue ) {
1020+ // Convert references to legacy hues to opacities (ie: foreground-4 to *-divider)
1021+ switch ( hue ) {
1022+ // hue-1 uses default opacity
1023+ case '2' :
1024+ opacity = 'secondary' ;
1025+ break ;
1026+ case '3' :
1027+ opacity = 'disabled' ;
1028+ break ;
1029+ case '4' :
1030+ opacity = 'divider' ;
1031+ }
9881032 }
1033+ hue = 'default' ;
9891034 }
9901035
9911036 // `default` is also accepted as a hue-value, because the background palettes are
@@ -994,7 +1039,42 @@ function parseRules(theme, colorType, rules) {
9941039 hue = theme . colors [ colorType ] . hues [ hue ] ;
9951040 }
9961041
997- return rgba ( ( PALETTES [ theme . colors [ colorType ] . name ] [ hue ] || '' ) [ contrast ? 'contrast' : 'value' ] , opacity ) ;
1042+ var colorDetails = ( PALETTES [ theme . colors [ colorType ] . name ] [ hue ] || '' ) ;
1043+
1044+ // If user has specified a foreground color, use those
1045+ if ( colorType === 'background' && contrast && regexColorType !== 'foreground' && colorDetails . contrastType == defaultBgContrastType ) {
1046+ // Don't process if colorType was changed
1047+ switch ( opacity ) {
1048+ case 'secondary' :
1049+ case 'icon' :
1050+ if ( theme . foregroundPalette [ '2' ] ) {
1051+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ '2' ] ) ) ;
1052+ }
1053+ break ;
1054+ case 'disabled' :
1055+ case 'hint' :
1056+ if ( theme . foregroundPalette [ '3' ] ) {
1057+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ '3' ] ) ) ;
1058+ }
1059+ break ;
1060+ case 'divider' :
1061+ if ( theme . foregroundPalette [ '4' ] ) {
1062+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ '4' ] ) ) ;
1063+ }
1064+ break ;
1065+ default :
1066+ if ( theme . foregroundPalette [ '1' ] ) {
1067+ return rgba ( colorToRgbaArray ( theme . foregroundPalette [ '1' ] ) ) ;
1068+ }
1069+ break ;
1070+ }
1071+ }
1072+
1073+ if ( contrast && opacity ) {
1074+ opacity = colorDetails . opacity [ opacity ] || opacity ;
1075+ }
1076+
1077+ return rgba ( colorDetails [ contrast ? 'contrast' : 'value' ] , opacity ) ;
9981078 } ) ;
9991079
10001080 // Matches '{{ primary-color }}', etc
@@ -1004,10 +1084,13 @@ function parseRules(theme, colorType, rules) {
10041084 // For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3)
10051085 angular . forEach ( [ 'default' , 'hue-1' , 'hue-2' , 'hue-3' ] , function ( hueName ) {
10061086 var newRule = rules
1007- . replace ( hueRegex , function ( match , _ , matchedColorType , hueType , opacity ) {
1087+ . replace ( hueRegex , function ( match , _ , matchedColorType , hueType , contrast , opacity ) {
10081088 var color = theme . colors [ matchedColorType ] ;
10091089 var palette = PALETTES [ color . name ] ;
10101090 var hueValue = color . hues [ hueName ] ;
1091+ if ( contrast && opacity ) {
1092+ opacity = palette [ hueValue ] . opacity [ opacity ] || opacity ;
1093+ }
10111094 return rgba ( palette [ hueValue ] [ hueType === 'color' ? 'value' : 'contrast' ] , opacity ) ;
10121095 } ) ;
10131096 if ( hueName !== 'default' ) {
@@ -1114,6 +1197,37 @@ function generateAllThemes($injector, $mdTheming) {
11141197 delete palette . contrastStrongLightColors ;
11151198 delete palette . contrastDarkColors ;
11161199
1200+ function getContrastType ( hueName ) {
1201+ if ( defaultContrast === 'light' ? darkColors . indexOf ( hueName ) !== - 1 : lightColors . indexOf ( hueName ) === - 1 ) {
1202+ return 'dark' ;
1203+ }
1204+ if ( strongLightColors . indexOf ( hueName ) !== - 1 ) {
1205+ return 'strongLight' ;
1206+ }
1207+ return 'light' ;
1208+ }
1209+ function getContrastColor ( contrastType ) {
1210+ switch ( contrastType ) {
1211+ default :
1212+ case 'strongLight' :
1213+ return STRONG_LIGHT_CONTRAST_COLOR ;
1214+ case 'light' :
1215+ return LIGHT_CONTRAST_COLOR ;
1216+ case 'dark' :
1217+ return DARK_CONTRAST_COLOR ;
1218+ }
1219+ }
1220+ function getOpacityValues ( contrastType ) {
1221+ switch ( contrastType ) {
1222+ default :
1223+ case 'strongLight' :
1224+ return STRONG_LIGHT_CONTRAST_OPACITY ;
1225+ case 'light' :
1226+ return LIGHT_CONTRAST_OPACITY ;
1227+ case 'dark' :
1228+ return DARK_CONTRAST_OPACITY ;
1229+ }
1230+ }
11171231 // Change { 'A100': '#fffeee' } to { 'A100': { value: '#fffeee', contrast:DARK_CONTRAST_COLOR }
11181232 angular . forEach ( palette , function ( hueValue , hueName ) {
11191233 if ( angular . isObject ( hueValue ) ) return ; // Already converted
@@ -1126,28 +1240,14 @@ function generateAllThemes($injector, $mdTheming) {
11261240 . replace ( '%3' , hueName ) ) ;
11271241 }
11281242
1243+ var contrastType = getContrastType ( hueName ) ;
11291244 palette [ hueName ] = {
11301245 hex : palette [ hueName ] ,
11311246 value : rgbValue ,
1132- contrast : getContrastColor ( )
1247+ contrastType : contrastType ,
1248+ contrast : getContrastColor ( contrastType ) ,
1249+ opacity : getOpacityValues ( contrastType )
11331250 } ;
1134- function getContrastColor ( ) {
1135- if ( defaultContrast === 'light' ) {
1136- if ( darkColors . indexOf ( hueName ) > - 1 ) {
1137- return DARK_CONTRAST_COLOR ;
1138- } else {
1139- return strongLightColors . indexOf ( hueName ) > - 1 ? STRONG_LIGHT_CONTRAST_COLOR
1140- : LIGHT_CONTRAST_COLOR ;
1141- }
1142- } else {
1143- if ( lightColors . indexOf ( hueName ) > - 1 ) {
1144- return strongLightColors . indexOf ( hueName ) > - 1 ? STRONG_LIGHT_CONTRAST_COLOR
1145- : LIGHT_CONTRAST_COLOR ;
1146- } else {
1147- return DARK_CONTRAST_COLOR ;
1148- }
1149- }
1150- }
11511251 } ) ;
11521252 }
11531253}
0 commit comments