diff --git a/superset/assets/javascripts/explore/components/controls/ColorPickerControl.jsx b/superset/assets/javascripts/explore/components/controls/ColorPickerControl.jsx new file mode 100644 index 000000000000..ecccc8e33ccc --- /dev/null +++ b/superset/assets/javascripts/explore/components/controls/ColorPickerControl.jsx @@ -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 ( + + i < 7)} + /> + ); + } + 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 ( +
+ + +
+
+
+
+ +
+ ); + } +} + +ColorPickerControl.propTypes = propTypes; +ColorPickerControl.defaultProps = defaultProps; diff --git a/superset/assets/javascripts/explore/components/controls/index.js b/superset/assets/javascripts/explore/components/controls/index.js index e2840fbc52bb..876bc4a1c631 100644 --- a/superset/assets/javascripts/explore/components/controls/index.js +++ b/superset/assets/javascripts/explore/components/controls/index.js @@ -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'; @@ -17,6 +18,7 @@ const controlMap = { BoundsControl, CheckboxControl, CollectionControl, + ColorPickerControl, ColorSchemeControl, DatasourceControl, DateFilterControl, diff --git a/superset/assets/javascripts/explore/main.css b/superset/assets/javascripts/explore/main.css index bc67249e75bd..a6afe5eba935 100644 --- a/superset/assets/javascripts/explore/main.css +++ b/superset/assets/javascripts/explore/main.css @@ -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; +} diff --git a/superset/assets/javascripts/explore/stores/controls.jsx b/superset/assets/javascripts/explore/stores/controls.jsx index d2851ee7247e..5107360475ea 100644 --- a/superset/assets/javascripts/explore/stores/controls.jsx +++ b/superset/assets/javascripts/explore/stores/controls.jsx @@ -1322,6 +1322,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'), diff --git a/superset/assets/javascripts/modules/colors.js b/superset/assets/javascripts/modules/colors.js index 803b6836d6b2..663fd6e4947c 100644 --- a/superset/assets/javascripts/modules/colors.js +++ b/superset/assets/javascripts/modules/colors.js @@ -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 diff --git a/superset/assets/package.json b/superset/assets/package.json index 3dfdb78240f9..9ae69dccb491 100644 --- a/superset/assets/package.json +++ b/superset/assets/package.json @@ -71,8 +71,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", diff --git a/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx new file mode 100644 index 000000000000..9ce2f478645f --- /dev/null +++ b/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx @@ -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(); + 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); + }); +}); diff --git a/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx new file mode 100644 index 000000000000..1f5ee69f6c96 --- /dev/null +++ b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx @@ -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(); + }); + + it('renders a Creatable', () => { + expect(wrapper.find(Creatable)).to.have.length(1); + }); +});