Skip to content

Instantly share code, notes, and snippets.

@AprilArcus
Last active August 29, 2015 14:17
Show Gist options
  • Save AprilArcus/9f7affd7bfe7680de27d to your computer and use it in GitHub Desktop.
Save AprilArcus/9f7affd7bfe7680de27d to your computer and use it in GitHub Desktop.
/* eslint-env es6 */
import { lighten, darken } from './colorHelpers'
// like twitter bootstrap
// https://github.com/twbs/bootstrap/blob/f5beebe726aa8c1810015d8c62931f4559b49664/less/variables.less
const variables = {};
variables.gray = {};
variables.gray.base = '#000'; // ln 10
variables.gray.darker = lighten(variables.gray.base, 13.5); // ln 11
variables.gray.dark = lighten(variables.gray.base, 20); // ln 12
variables.gray.gray = lighten(variables.gray.base, 33.5); // ln 13
variables.gray.light = lighten(variables.gray.base, 46.7); // ln 14
variables.gray.lighter = lighten(variables.gray.base, 93.5); // ln 15
variables.brand = {};
variables.brand.primary = darken('#428bca', 6.5); // ln 17
variables.brand.success = '#5cb85c'; // ln 18
variables.brand.info = '#5bc0de'; // ln 19
variables.brand.warning = '#f0ad4e'; // ln 20
variables.brand.danger = '#d9534f'; // ln 21
variables.link = {hover: {}};
variables.link.color = variables.brand.primary; // ln 34
variables.link.hover.color = darken(variables.link.color, 15); // ln 36
variables.link.hover.decoration = 'underline'; // ln 38
variables.font_size = {};
variables.font_size.base = 14; // ln 51
variables.font_size.large = Math.ceil(variables.font_size.base * 1.25); // ln 52
variables.font_size.small = Math.ceil(variables.font_size.base * 0.85); // ln 53
variables.font_size.tiny = variables.font_size.small;
variables.line_height = {};
variables.line_height.base = 1.428571429; // ln 63
variables.line_height.large = 1.5; // ln 102
variables.line_height.small = 1.3333333; // ln 103
variables.line_height.tiny = variables.line_height.small;
variables.line_height_computed = variables.line_height.base *
variables.font_size.base; // ln 65
variables.padding = {base: {}, large: {}, small: {}, tiny: {}};
variables.padding.base.vertical = 6; // ln 90
variables.padding.base.horizontal = 12; // ln 91
variables.padding.large.vertical = 10; // ln 93
variables.padding.large.horizontal = 16; // ln 94
variables.padding.small.vertical = 5; // ln 96
variables.padding.small.horizontal = 10; // ln 97
variables.padding.tiny.vertical = 1; // ln 99
variables.padding.tiny.horizontal = 5; // ln 100
variables.border_radius = {};
variables.border_radius.base = 4; // ln 105
variables.border_radius.large = 6; // ln 106
variables.border_radius.small = 3; // ln 107
variables.border_radius.tiny = variables.border_radius.small;
variables.btn = {default: {}, primary: {}, success: {}, info: {},
warning: {}, danger: {}};
variables.btn.font_weight = 'normal'; // ln 145
variables.btn.default.color = '#333'; // ln 147
variables.btn.default.bg = '#fff'; // ln 148
variables.btn.default.border = '#ccc'; // ln 149
variables.btn.primary.color = '#fff'; // ln 151
variables.btn.primary.bg = variables.brand.primary; // ln 152
variables.btn.primary.border = darken(variables.btn.primary.bg, 5); // ln 149
variables.btn.success.color = '#fff'; // ln 155
variables.btn.success.bg = variables.brand.success; // ln 156fc
variables.btn.success.border = darken(variables.btn.success.bg, 5); // ln 157
variables.btn.info.color = '#fff'; // ln 159
variables.btn.info.bg = variables.brand.info; // ln 160
variables.btn.info.border = darken(variables.btn.info.bg, 5); // ln 161
variables.btn.warning.color = '#fff'; // ln 163
variables.btn.warning.bg = variables.brand.warning; // ln 164
variables.btn.warning.border = darken(variables.btn.warning.bg, 5); // ln 164
variables.btn.danger.color = '#fff'; // ln 167
variables.btn.danger.bg = variables.brand.danger; // ln 168
variables.btn.danger.border = darken(variables.btn.danger.bg, 5); // ln 169
variables.btn.link = {disabled: {color: variables.gray.light}}; // ln 171
variables.cursor = {disabled: 'not-allowed'}; // ln 222
export default variables;
/* eslint-env es6 */
import React from 'react';
import { addons } from 'react/addons';
const PureRenderMixin = addons.PureRenderMixin;
import { lighten, darken } from './colorHelpers'
import variables from './bootstrapVariables'
export default React.createClass({
mixins: [PureRenderMixin],
propTypes: {
bsSize: React.PropTypes.oneOf(['base', 'large', 'small', 'tiny']),
bsStyle: React.PropTypes.oneOf(['default', 'primary', 'success', 'info',
'warning', 'danger', 'link']),
disabled: React.PropTypes.bool
},
getDefaultProps() {
return {bsStyle: 'default', bsSize: 'base'};
},
getInitialState() {
return {
hover: false,
active: false,
focus: false
};
},
linkStyle() {
// styles for buttons disguised as links
// https://github.com/twbs/bootstrap/blob/65721f531536e05026b1ae5f0359955c78d13156/less/buttons.less
// ll 84-121
const style = {
color: variables.link.color, // ln 89
fontWeight: 'normal', // ln 90
backgroundColor: 'transparent' // lns 98, 111
};
if (this.props.disabled) {
style.color = variables.btn.link.disabled.color; // ln 117
} else {
if (this.state.hover || this.state.focus) {
style.color = variables.link.hover.color; // ln 109
style.textDecoration = variables.link.hover.decoration; // ln 110
}
}
return style;
},
buttonStyle() {
// styles specific to button-type buttons (i.e., colored roundrects)
// original less styles implemented in
// https://github.com/twbs/bootstrap/blob/9ed9eb97ee09e514da942d680dac032628124816/less/mixins/buttons.less
// ll 6-54
// https://github.com/twbs/bootstrap/blob/65721f531536e05026b1ae5f0359955c78d13156/less/buttons.less
// ll 57-81
const style = {
color: variables.btn[this.props.bsStyle].color, // ln 7
backgroundColor: variables.btn[this.props.bsStyle].bg, // ln 8
borderColor: variables.btn[this.props.bsStyle].border, // ln 9
borderRadius: variables.border_radius[this.props.bsSize],
fontWeight: variables.btn.font_weight // ln 12
};
if (!this.props.disabled) {
if (this.state.hover || this.state.active || this.state.focus) { // ll 11-15
style.backgroundColor = darken(style.backgroundColor, 10); // ln 18
style.borderColor = darken(style.borderColor, 12); // ln 19
}
if (this.state.active) {
style.outline = 0; // ln 41
style.boxShadow = 'inset 0 3px 5px rgba(0,0,0,.125)'; // ln 43
}
}
return style;
},
style() {
// https://github.com/twbs/bootstrap/blob/65721f531536e05026b1ae5f0359955c78d13156/less/buttons.less
const baseStyle = {
display: 'inline-block', // ln 10
marginBottom: 0, // ln 11
padding: `${variables.padding[this.props.bsSize].vertical}px ${variables.padding[this.props.bsSize].horizontal}px`,
fontSize: variables.font_size[this.props.bsSize],
lineHeight: variables.line_height[this.props.bsSize],
textAlign: 'center', // ln 13
verticalAlign: 'middle', // ln 14
touchAction: 'manipulation', // ln 15
cursor: 'pointer', // ln 16
backgroundImage: 'none', // ln 17
borderWidth: 1, // ln 18
borderStyle: 'solid', // ln 18
borderColor: 'transparent', // ln 18
whiteSpace: 'nowrap' // ln 19
};
if (this.props.disabled) {
baseStyle.cursor = variables.cursor.disabled; // ln 49
baseStyle.pointerEvents = 'none'; // ln 50
baseStyle.opacity = 0.65; // ln 51
}
if (this.props.bsStyle === 'link') {
return Object.assign(baseStyle, this.linkStyle(), this.props.style);
} else {
return Object.assign(baseStyle, this.buttonStyle(), this.props.style);
}
},
render() {
return <input {...this.props}
style={this.style()}
type="button"
disabled={this.state.disabled}
onMouseEnter={() => this.setState({hover: true})}
onMouseLeave={() => this.setState({hover: false, active: false})}
onMouseDown={() => this.setState({active: true})}
onMouseUp={() => this.setState({active: false})}
onFocus={() => this.setState({focus: true})}
onBlur={() => this.setState({focus: false})} />;
}
});
/* eslint-env es6 */
// some helper functions, in the style of less
function hslTriple2hexString(h, s, l) {
const h6 = h * 6;
const c = (1 - Math.abs(2 * l - 1)) * s;
const x = c * (1 - Math.abs(h6 % 2 - 1));
const m = l - c / 2;
let r, g, b;
if (h6 < 1) {
[r, g, b] = [c, x, 0];
} else if (h6 < 2) {
[r, g, b] = [x, c, 0];
} else if (h6 < 3) {
[r, g, b] = [0, c, x];
} else if (h6 < 4) {
[r, g, b] = [0, x, c];
} else if (h6 < 5) {
[r, g, b] = [x, 0, c];
} else {
[r, g, b] = [c, 0, x];
}
const rgb = [r, g, b].map(c => Math.round((c + m) * 255));
return `#${rgb.map(c => c.toString(16)).map((s) => {
return (s.length === 1) ? '0' + s : s;
}).join('')}`;
}
function hexString2rgbTriple(string) {
if (string.length === 4 || string.length === 7) {
string = string.slice(1);
}
let stringTriple;
if (string.length === 3) {
stringTriple = string.split('').map( c => c + c );
} else if (string.length === 6) {
stringTriple = [string.slice(0, 2),
string.slice(2, 4),
string.slice(4, 6)];
} else {
throw new Error('malformed input rgb string');
}
return stringTriple.map( c => parseInt(c, 16) / 255 );
}
function rgbTriple2hslTriple([r, g, b]) {
const max = (r > g && r > b) ? r : ((g > b) ? g : b);
const min = (r < g && r < b) ? r : ((g < b) ? g : b);
const l = (max + min) / 2;
const deltaMax = max - min;
if (deltaMax === 0) return [0, 0, 1]; // achromatic
const s = (l < 0.5) ? (deltaMax / (max + min)) : deltaMax / (2 - max - min);
let h;
switch(max) {
case r: h = (g - b) / deltaMax + (g < b ? 6 : 0); break;
case g: h = (b - r) / deltaMax + 2; break;
case b: h = (r - g) / deltaMax + 4; break;
}
h /= 6;
return [h, s, l];
}
export function lighten(rgbHexString, percent) {
const [h, s, l] = rgbTriple2hslTriple(hexString2rgbTriple(rgbHexString));
let lightened = l + percent / 100;
lightened = (lightened > 1.0) ? 1.0 : lightened;
return hslTriple2hexString(h, s, lightened);
}
export function darken(rgbHexString, percent) {
const [h, s, l] = rgbTriple2hslTriple(hexString2rgbTriple(rgbHexString));
let darkened = l - percent / 100;
darkened = (darkened < 0) ? 0 : darkened;
return hslTriple2hexString(h, s, darkened);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment