Skip to content

Commit

Permalink
Add a ColorPickerControl (#3653)
Browse files Browse the repository at this point in the history
* Add a ColorPickerControl

* Tests
  • Loading branch information
mistercrunch authored Oct 16, 2017
1 parent bad6938 commit d0b5b44
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { SketchPicker } from 'react-color';

import ControlHeader from '../ControlHeader';
import { bnbColors } from '../../../modules/colors';

const propTypes = {
onChange: PropTypes.func,
value: PropTypes.object,
};

const defaultProps = {
onChange: () => {},
};

const swatchCommon = {
position: 'absolute',
width: '50px',
height: '20px',
top: '0px',
left: '0px',
right: '0px',
bottom: '0px',
};

const styles = {
swatch: {
width: '50px',
height: '20px',
position: 'relative',
padding: '5px',
borderRadius: '1px',
display: 'inline-block',
cursor: 'pointer',
boxShadow: 'rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset, rgba(0, 0, 0, 0.25) 0px 0px 4px inset',
},
color: {
...swatchCommon,
borderRadius: '2px',
},
checkboard: {
...swatchCommon,
background: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==") left center',
},
};
export default class ColorPickerControl extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
}
onChange(col) {
this.props.onChange(col.rgb);
}
renderPopover() {
return (
<Popover id="filter-popover" className="color-popover">
<SketchPicker
color={this.props.value}
onChange={this.onChange}
presetColors={bnbColors.filter((s, i) => i < 7)}
/>
</Popover>);
}
render() {
const c = this.props.value || { r: 0, g: 0, b: 0, a: 0 };
const colStyle = Object.assign(
{}, styles.color, { background: `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})` });
return (
<div>
<ControlHeader {...this.props} />
<OverlayTrigger
container={document.body}
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
>
<div style={styles.swatch}>
<div style={styles.checkboard} />
<div style={colStyle} />
</div>
</OverlayTrigger>
</div>
);
}
}

ColorPickerControl.propTypes = propTypes;
ColorPickerControl.defaultProps = defaultProps;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BoundsControl from './BoundsControl';
import CheckboxControl from './CheckboxControl';
import CollectionControl from './CollectionControl';
import ColorPickerControl from './ColorPickerControl';
import ColorSchemeControl from './ColorSchemeControl';
import DatasourceControl from './DatasourceControl';
import DateFilterControl from './DateFilterControl';
Expand All @@ -17,6 +18,7 @@ const controlMap = {
BoundsControl,
CheckboxControl,
CollectionControl,
ColorPickerControl,
ColorSchemeControl,
DatasourceControl,
DateFilterControl,
Expand Down
8 changes: 8 additions & 0 deletions superset/assets/javascripts/explore/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,11 @@
.list-group {
margin-bottom: 10px;
}
.color-popover.popover {
border: none;
background-color: transparent;
}
.color-popover .popover-content {
padding: 0;
background-color: transparent;
}
6 changes: 6 additions & 0 deletions superset/assets/javascripts/explore/stores/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,12 @@ export const controls = {
description: t('The color for points and clusters in RGB'),
},

color: {
type: 'ColorPickerControl',
label: t('Color'),
description: t('Pick a color'),
},

ranges: {
type: 'TextControl',
label: t('Ranges'),
Expand Down
2 changes: 1 addition & 1 deletion superset/assets/javascripts/modules/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import d3 from 'd3';
export const brandColor = '#00A699';

// Color related utility functions go in this object
const bnbColors = [
export const bnbColors = [
'#ff5a5f', // rausch
'#7b0051', // hackb
'#007A87', // kazan
Expand Down
3 changes: 2 additions & 1 deletion superset/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@
"react-alert": "^2.3.0",
"react-bootstrap": "^0.31.2",
"react-bootstrap-table": "^4.0.2",
"react-dom": "^15.6.2",
"react-color": "^2.13.8",
"react-datetime": "2.9.0",
"react-dom": "^15.6.2",
"react-gravatar": "^2.6.1",
"react-grid-layout": "^0.14.4",
"react-map-gl": "^3.0.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* eslint-disable no-unused-expressions */
import React from 'react';
import { expect } from 'chai';
import { describe, it, beforeEach } from 'mocha';
import { shallow } from 'enzyme';
import { OverlayTrigger } from 'react-bootstrap';
import { SketchPicker } from 'react-color';

import ColorPickerControl from
'../../../../javascripts/explore/components/controls/ColorPickerControl';
import ControlHeader from '../../../../javascripts/explore/components/ControlHeader';

const defaultProps = {
value: { },
};

describe('ColorPickerControl', () => {
let wrapper;
let inst;
beforeEach(() => {
wrapper = shallow(<ColorPickerControl {...defaultProps} />);
inst = wrapper.instance();
});

it('renders a OverlayTrigger', () => {
const controlHeader = wrapper.find(ControlHeader);
expect(controlHeader).to.have.lengthOf(1);
expect(wrapper.find(OverlayTrigger)).to.have.length(1);
});

it('renders a OverlayTrigger', () => {
const controlHeader = wrapper.find(ControlHeader);
expect(controlHeader).to.have.lengthOf(1);
expect(wrapper.find(OverlayTrigger)).to.have.length(1);
});

it('renders a Popover with a SketchPicker', () => {
const popOver = shallow(inst.renderPopover());
expect(popOver.find(SketchPicker)).to.have.lengthOf(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable no-unused-expressions */
import React from 'react';
import { expect } from 'chai';
import { describe, it, beforeEach } from 'mocha';
import { mount } from 'enzyme';
import { Creatable } from 'react-select';

import ColorSchemeControl from
'../../../../javascripts/explore/components/controls/ColorSchemeControl';
import { ALL_COLOR_SCHEMES } from '../../../../javascripts/modules/colors';

const defaultProps = {
options: Object.keys(ALL_COLOR_SCHEMES).map(s => ([s, s])),
};

describe('ColorSchemeControl', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<ColorSchemeControl {...defaultProps} />);
});

it('renders a Creatable', () => {
expect(wrapper.find(Creatable)).to.have.length(1);
});
});

0 comments on commit d0b5b44

Please sign in to comment.