th-vue-material
Version:
Material Design for Vue.js
192 lines (160 loc) • 4.66 kB
JavaScript
import palette from './palette';
import rgba from './rgba';
import mdTheme from './mdTheme';
import { changeHtmlMetaColor, createNewStyleElement } from './dom';
const VALID_THEME_TYPE = ['primary', 'accent', 'background', 'warn', 'hue-1', 'hue-2', 'hue-3'];
const TYPE_REGEX = new RegExp('(' + VALID_THEME_TYPE.join('|').toUpperCase() + ')-(COLOR|CONTRAST)-?(A?\\d*)-?(\\d*\\.?\\d+)?', 'g');
const DEFAULT_THEME_COLORS = {
primary: 'indigo',
accent: 'pink',
background: 'white',
warn: 'deep-orange'
};
/*const DEFAULT_HUES = {
accent: {
'hue-1': 'A100',
'hue-2': 'A400',
'hue-3': 'A700'
},
background: {
'hue-1': 'A100',
'hue-2': '100',
'hue-3': '300'
}
};*/
const registeredPrimaryColor = {};
const injectedStyles = {};
const parseStyle = (style, theme, name) => {
return style.replace(TYPE_REGEX, (match, type, colorType, hue, opacity) => {
let color;
let colorVariant = +hue === 0 ? 500 : hue;
type = type.toLowerCase();
if (theme[type]) {
if (typeof theme[type] === 'string') {
color = palette[theme[type]];
} else {
color = palette[theme[type].color] || palette[DEFAULT_THEME_COLORS[type]];
colorVariant = +hue === 0 ? theme[type].hue : hue;
}
} else {
color = palette[DEFAULT_THEME_COLORS[type]];
}
if (colorType === 'COLOR') {
let isDefault = palette[theme[type]];
if (!colorVariant && !isDefault) {
if (type === 'accent') {
colorVariant = 'A200';
} else if (type === 'background') {
colorVariant = 50;
}
}
if (type === 'primary') {
registeredPrimaryColor[name] = color[colorVariant];
}
if (opacity) {
return rgba(color[colorVariant], opacity);
}
return color[colorVariant];
}
let isDarkText = color.darkText.indexOf(colorVariant) >= 0;
if (theme[type] && typeof theme[type] !== 'string' && theme[type].textColor) {
if (theme[type].textColor === 'black') {
isDarkText = true;
} else if (theme[type].textColor === 'white') {
isDarkText = false;
}
}
if (isDarkText) {
if (opacity) {
return rgba('#000', opacity);
}
return 'rgba(0, 0, 0, .87)';
}
if (opacity) {
return rgba('#fff', opacity);
}
return 'rgba(255, 255, 255, .87)';
});
};
function warnNotFound(themeName) {
console.warn(`The theme '${themeName}' doesn't exists. You need to register` +
' it first in order to use.');
}
function injectStyle(style, spec, name, styleId) {
if (createNewStyleElement) {
style = parseStyle(style, spec, name);
style = style.replace(/THEME_NAME/g, styleId);
createNewStyleElement(style, styleId);
}
}
export default function install(Vue) {
Vue.material = new Vue({
data: {
currentTheme: 'default',
inkRipple: true,
prefix: 'md-theme-',
styles: [],
themes: {
default: DEFAULT_THEME_COLORS
}
},
watch: {
styles() {
this.refreshInjectedStyles();
}
},
methods: {
registerPalette(name, spec) {
palette[name] = spec;
},
<<<<<<< Updated upstream
useTheme(name) {
if (name in injectedStyles) {
return;
}
const spec = this.themes[name];
=======
registerTheme(name, spec) {
let theme = {};
>>>>>>> Stashed changes
if (!spec) {
return warnNotFound(name);
}
injectStyle(this.styles.join('\n'), spec, name, this.prefix + name);
return injectedStyles[name] = true;
},
refreshInjectedStyles() {
const styles = this.styles.join('\n');
const prefix = this.prefix;
Object.keys(injectedStyles).forEach((name) => {
const spec = this.themes[name];
injectStyle(styles, spec, name, prefix + name);
});
},
registerTheme(name, spec) {
if (typeof name === 'string') {
this.themes[name] = spec;
} else {
Object.keys(name).forEach((k) => this.themes[k] = name[k]);
}
},
setCurrentTheme(name) {
if (name === this.currentTheme) {
return;
}
const prefix = this.prefix;
this.useTheme(name);
if (changeHtmlMetaColor) {
changeHtmlMetaColor(
registeredPrimaryColor[name],
prefix + this.currentTheme,
prefix + name
);
}
this.currentTheme = name;
}
}
});
Vue.component('md-theme', mdTheme);
Vue.prototype.$material = Vue.material;
}