Commit b4d51c9f by Uchechukwu Obasi Committed by GitHub

ColorPicker: migrated styles from sass to emotion (#30909)

* ColorPicker: migrated styles from sass to emotion

* fixes frontend test

* updated some changes

* updated some changes

* fixed small import nits
parent ef8a5b76
...@@ -3,10 +3,11 @@ import omit from 'lodash/omit'; ...@@ -3,10 +3,11 @@ import omit from 'lodash/omit';
import { PopoverController } from '../Tooltip/PopoverController'; import { PopoverController } from '../Tooltip/PopoverController';
import { Popover } from '../Tooltip/Popover'; import { Popover } from '../Tooltip/Popover';
import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover'; import { ColorPickerPopover, ColorPickerProps, ColorPickerChangeHandler } from './ColorPickerPopover';
import { getColorForTheme } from '@grafana/data'; import { getColorForTheme, GrafanaTheme } from '@grafana/data';
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover'; import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
import { withTheme } from '../../themes/ThemeContext'; import { css } from 'emotion';
import { withTheme, stylesFactory } from '../../themes';
import { ColorPickerTrigger } from './ColorPickerTrigger'; import { ColorPickerTrigger } from './ColorPickerTrigger';
/** /**
...@@ -40,6 +41,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>( ...@@ -40,6 +41,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
render() { render() {
const { theme, children } = this.props; const { theme, children } = this.props;
const styles = getStyles(theme);
const popoverElement = React.createElement(popover, { const popoverElement = React.createElement(popover, {
...omit(this.props, 'children'), ...omit(this.props, 'children'),
onChange: this.onColorChange, onChange: this.onColorChange,
...@@ -54,7 +56,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>( ...@@ -54,7 +56,7 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
<Popover <Popover
{...popperProps} {...popperProps}
referenceElement={this.pickerTriggerRef.current} referenceElement={this.pickerTriggerRef.current}
wrapperClassName="ColorPicker" wrapperClassName={styles.colorPicker}
onMouseLeave={hidePopper} onMouseLeave={hidePopper}
onMouseEnter={showPopper} onMouseEnter={showPopper}
/> />
...@@ -88,3 +90,32 @@ export const colorPickerFactory = <T extends ColorPickerProps>( ...@@ -88,3 +90,32 @@ export const colorPickerFactory = <T extends ColorPickerProps>(
export const ColorPicker = withTheme(colorPickerFactory(ColorPickerPopover, 'ColorPicker')); export const ColorPicker = withTheme(colorPickerFactory(ColorPickerPopover, 'ColorPicker'));
export const SeriesColorPicker = withTheme(colorPickerFactory(SeriesColorPickerPopover, 'SeriesColorPicker')); export const SeriesColorPicker = withTheme(colorPickerFactory(SeriesColorPickerPopover, 'SeriesColorPicker'));
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
colorPicker: css`
position: absolute;
z-index: ${theme.zIndex.tooltip};
color: ${theme.colors.text};
max-width: 400px;
font-size: ${theme.typography.size.sm};
// !important because these styles are also provided to popper via .popper classes from Tooltip component
// hope to get rid of those soon
padding: 15px !important;
& [data-placement^='top'] {
padding-left: 0 !important;
padding-right: 0 !important;
}
& [data-placement^='bottom'] {
padding-left: 0 !important;
padding-right: 0 !important;
}
& [data-placement^='left'] {
padding-top: 0 !important;
}
& [data-placement^='right'] {
padding-top: 0 !important;
}
`,
};
});
...@@ -3,16 +3,14 @@ import { mount, ReactWrapper } from 'enzyme'; ...@@ -3,16 +3,14 @@ import { mount, ReactWrapper } from 'enzyme';
import { ColorPickerPopover } from './ColorPickerPopover'; import { ColorPickerPopover } from './ColorPickerPopover';
import { ColorSwatch } from './NamedColorsGroup'; import { ColorSwatch } from './NamedColorsGroup';
import flatten from 'lodash/flatten'; import flatten from 'lodash/flatten';
import { getTheme } from '../../themes'; import { getNamedColorPalette, getColorFromHexRgbOrName } from '@grafana/data';
import { GrafanaThemeType, getNamedColorPalette, getColorFromHexRgbOrName } from '@grafana/data';
const allColors = flatten(Array.from(getNamedColorPalette().values())); const allColors = flatten(Array.from(getNamedColorPalette().values()));
describe('ColorPickerPopover', () => { describe('ColorPickerPopover', () => {
describe('rendering', () => { describe('rendering', () => {
it('should render provided color as selected if color provided by name', () => { it('should render provided color as selected if color provided by name', () => {
const theme = getTheme(); const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} />);
const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} theme={theme} />);
const selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green'); const selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green');
const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false); const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false);
...@@ -22,8 +20,7 @@ describe('ColorPickerPopover', () => { ...@@ -22,8 +20,7 @@ describe('ColorPickerPopover', () => {
}); });
it('should render provided color as selected if color provided by hex', () => { it('should render provided color as selected if color provided by hex', () => {
const theme = getTheme(); const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} />);
const wrapper = mount(<ColorPickerPopover color={'green'} onChange={() => {}} theme={theme} />);
const selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green'); const selectedSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green');
const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false); const notSelectedSwatches = wrapper.find(ColorSwatch).filterWhere((node) => node.prop('isSelected') === false);
...@@ -44,26 +41,17 @@ describe('ColorPickerPopover', () => { ...@@ -44,26 +41,17 @@ describe('ColorPickerPopover', () => {
}); });
it('should pass hex color value to onChange prop by default', () => { it('should pass hex color value to onChange prop by default', () => {
wrapper = mount( wrapper = mount(<ColorPickerPopover color={'green'} onChange={onChangeSpy} />);
<ColorPickerPopover color={'green'} onChange={onChangeSpy} theme={getTheme(GrafanaThemeType.Light)} />
);
const basicBlueSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green'); const basicBlueSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green');
basicBlueSwatch.simulate('click'); basicBlueSwatch.simulate('click');
expect(onChangeSpy).toBeCalledTimes(1); expect(onChangeSpy).toBeCalledTimes(1);
expect(onChangeSpy).toBeCalledWith(getColorFromHexRgbOrName('green', GrafanaThemeType.Light)); expect(onChangeSpy).toBeCalledWith(getColorFromHexRgbOrName('green'));
}); });
it('should pass color name to onChange prop when named colors enabled', () => { it('should pass color name to onChange prop when named colors enabled', () => {
wrapper = mount( wrapper = mount(<ColorPickerPopover enableNamedColors color={'green'} onChange={onChangeSpy} />);
<ColorPickerPopover
enableNamedColors
color={'green'}
onChange={onChangeSpy}
theme={getTheme(GrafanaThemeType.Light)}
/>
);
const basicBlueSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green'); const basicBlueSwatch = wrapper.find(ColorSwatch).findWhere((node) => node.key() === 'green');
basicBlueSwatch.simulate('click'); basicBlueSwatch.simulate('click');
......
...@@ -4,7 +4,9 @@ import { PopoverContentProps } from '../Tooltip/Tooltip'; ...@@ -4,7 +4,9 @@ import { PopoverContentProps } from '../Tooltip/Tooltip';
import SpectrumPalette from './SpectrumPalette'; import SpectrumPalette from './SpectrumPalette';
import { Themeable } from '../../types/theme'; import { Themeable } from '../../types/theme';
import { warnAboutColorPickerPropsDeprecation } from './warnAboutColorPickerPropsDeprecation'; import { warnAboutColorPickerPropsDeprecation } from './warnAboutColorPickerPropsDeprecation';
import { GrafanaThemeType, getColorForTheme } from '@grafana/data'; import { css, cx } from 'emotion';
import { GrafanaTheme, GrafanaThemeType, getColorForTheme } from '@grafana/data';
import { stylesFactory, withTheme } from '../../themes';
export type ColorPickerChangeHandler = (color: string) => void; export type ColorPickerChangeHandler = (color: string) => void;
...@@ -36,7 +38,7 @@ interface State<T> { ...@@ -36,7 +38,7 @@ interface State<T> {
activePicker: PickerType | keyof T; activePicker: PickerType | keyof T;
} }
export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React.Component<Props<T>, State<T>> { class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends React.Component<Props<T>, State<T>> {
constructor(props: Props<T>) { constructor(props: Props<T>) {
super(props); super(props);
this.state = { this.state = {
...@@ -113,10 +115,15 @@ export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React ...@@ -113,10 +115,15 @@ export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React
render() { render() {
const { theme } = this.props; const { theme } = this.props;
const colorPickerTheme = theme.type || GrafanaThemeType.Dark; const styles = getStyles(theme);
return ( return (
<div className={`ColorPickerPopover ColorPickerPopover--${colorPickerTheme}`}> <div
<div className="ColorPickerPopover__tabs"> className={cx(
styles.colorPickerPopover,
theme.type === GrafanaThemeType.Light ? styles.colorPickerPopoverLight : styles.colorPickerPopoverDark
)}
>
<div className={styles.colorPickerPopoverTabs}>
<div className={this.getTabClassName('palette')} onClick={this.onTabChange('palette')}> <div className={this.getTabClassName('palette')} onClick={this.onTabChange('palette')}>
Colors Colors
</div> </div>
...@@ -126,8 +133,62 @@ export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React ...@@ -126,8 +133,62 @@ export class ColorPickerPopover<T extends CustomPickersDescriptor> extends React
{this.renderCustomPickerTabs()} {this.renderCustomPickerTabs()}
</div> </div>
<div className="ColorPickerPopover__content">{this.renderPicker()}</div> <div className={styles.colorPickerPopoverContent}>{this.renderPicker()}</div>
</div> </div>
); );
} }
} }
export const ColorPickerPopover = withTheme(UnThemedColorPickerPopover);
ColorPickerPopover.displayName = 'ColorPickerPopover';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
return {
colorPickerPopover: css`
border-radius: ${theme.border.radius.md};
`,
colorPickerPopoverLight: css`
color: ${theme.palette.black};
background: linear-gradient(180deg, ${theme.palette.white} 0%, #f7f8fa 104.25%);
box-shadow: 0px 2px 4px #dde4ed, 0px 0px 2px #dde4ed;
.ColorPickerPopover__tab {
width: 50%;
text-align: center;
padding: ${theme.spacing.sm} 0;
background: #dde4ed;
}
.ColorPickerPopover__tab--active {
background: ${theme.palette.white};
}
`,
colorPickerPopoverDark: css`
color: #d8d9da;
background: linear-gradient(180deg, #1e2028 0%, #161719 104.25%);
box-shadow: 0px 2px 4px ${theme.palette.black}, 0px 0px 2px ${theme.palette.black};
.ColorPickerPopover__tab {
width: 50%;
text-align: center;
padding: ${theme.spacing.sm} 0;
background: #303133;
color: ${theme.palette.white};
cursor: pointer;
}
.ColorPickerPopover__tab--active {
background: none;
}
`,
colorPickerPopoverContent: css`
width: 336px;
min-height: 184px;
padding: ${theme.spacing.lg};
`,
colorPickerPopoverTabs: css`
display: flex;
width: 100%;
border-radius: ${theme.border.radius.md} ${theme.border.radius.md} 0 0;
overflow: hidden;
`,
};
});
...@@ -3,7 +3,8 @@ import React, { FunctionComponent } from 'react'; ...@@ -3,7 +3,8 @@ import React, { FunctionComponent } from 'react';
import { ColorPickerPopover, ColorPickerProps } from './ColorPickerPopover'; import { ColorPickerPopover, ColorPickerProps } from './ColorPickerPopover';
import { PopoverContentProps } from '../Tooltip/Tooltip'; import { PopoverContentProps } from '../Tooltip/Tooltip';
import { Switch } from '../Forms/Legacy/Switch/Switch'; import { Switch } from '../Forms/Legacy/Switch/Switch';
import { withTheme } from '../../themes/ThemeContext'; import { css } from 'emotion';
import { withTheme, useStyles } from '../../themes';
export interface SeriesColorPickerPopoverProps extends ColorPickerProps, PopoverContentProps { export interface SeriesColorPickerPopoverProps extends ColorPickerProps, PopoverContentProps {
yaxis?: number; yaxis?: number;
...@@ -11,6 +12,7 @@ export interface SeriesColorPickerPopoverProps extends ColorPickerProps, Popover ...@@ -11,6 +12,7 @@ export interface SeriesColorPickerPopoverProps extends ColorPickerProps, Popover
} }
export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopoverProps> = (props) => { export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopoverProps> = (props) => {
const styles = useStyles(getStyles);
const { yaxis, onToggleAxis, color, ...colorPickerProps } = props; const { yaxis, onToggleAxis, color, ...colorPickerProps } = props;
const customPickers = onToggleAxis const customPickers = onToggleAxis
...@@ -22,8 +24,8 @@ export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopove ...@@ -22,8 +24,8 @@ export const SeriesColorPickerPopover: FunctionComponent<SeriesColorPickerPopove
<Switch <Switch
key="yaxisSwitch" key="yaxisSwitch"
label="Use right y-axis" label="Use right y-axis"
className="ColorPicker__axisSwitch" className={styles.colorPickerAxisSwitch}
labelClass="ColorPicker__axisSwitchLabel" labelClass={styles.colorPickerAxisSwitchLabel}
checked={yaxis === 2} checked={yaxis === 2}
onChange={() => { onChange={() => {
if (onToggleAxis) { if (onToggleAxis) {
...@@ -87,3 +89,15 @@ export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSel ...@@ -87,3 +89,15 @@ export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSel
// This component is to enable SeriesColorPickerPopover usage via series-color-picker-popover directive // This component is to enable SeriesColorPickerPopover usage via series-color-picker-popover directive
export const SeriesColorPickerPopoverWithTheme = withTheme(SeriesColorPickerPopover); export const SeriesColorPickerPopoverWithTheme = withTheme(SeriesColorPickerPopover);
const getStyles = () => {
return {
colorPickerAxisSwitch: css`
width: 100%;
`,
colorPickerAxisSwitchLabel: css`
display: flex;
flex-grow: 1;
`,
};
};
$arrowSize: 15px;
.ColorPicker {
@extend .popper;
font-size: 12px;
// !important because these styles are also provided to popper via .popper classes from Tooltip component
// hope to get rid of those soon
padding: $arrowSize !important;
}
.ColorPicker__arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 0px;
&[data-placement^='top'] {
border-width: $arrowSize $arrowSize 0 $arrowSize;
border-left-color: transparent;
border-right-color: transparent;
border-bottom-color: transparent;
bottom: -$arrowSize;
left: calc(50%-#{$arrowSize});
padding-top: $arrowSize;
}
&[data-placement^='bottom'] {
border-width: 0 $arrowSize $arrowSize $arrowSize;
border-left-color: transparent;
border-right-color: transparent;
border-top-color: transparent;
top: 0;
left: calc(50%-#{$arrowSize});
}
&[data-placement^='bottom-start'] {
border-width: 0 $arrowSize $arrowSize $arrowSize;
border-left-color: transparent;
border-right-color: transparent;
border-top-color: transparent;
top: 0;
left: $arrowSize;
}
&[data-placement^='bottom-end'] & {
border-width: 0 $arrowSize $arrowSize $arrowSize;
border-left-color: transparent;
border-right-color: transparent;
border-top-color: transparent;
top: 0;
left: calc(100%-#{$arrowSize});
}
&[data-placement^='right'] {
border-width: $arrowSize $arrowSize $arrowSize 0;
border-left-color: transparent;
border-top-color: transparent;
border-bottom-color: transparent;
left: 0;
top: calc(50%-#{$arrowSize});
}
&[data-placement^='left'] {
border-width: $arrowSize 0 $arrowSize $arrowSize;
border-top-color: transparent;
border-right-color: transparent;
border-bottom-color: transparent;
right: -$arrowSize;
top: calc(50%-#{$arrowSize});
}
}
.ColorPicker__arrow--light {
border-color: #ffffff;
}
.ColorPicker__arrow--dark {
border-color: #1e2028;
}
// !important because these styles are also provided to popper via .popper classes from Tooltip component
// hope to get rid of those soon
.ColorPicker[data-placement^='top'],
.ColorPicker[data-placement^='bottom'] {
padding-left: 0 !important;
padding-right: 0 !important;
}
// !important because these styles are also provided to popper via .popper classes from Tooltip component
// hope to get rid of those soon
.ColorPicker[data-placement^='left'],
.ColorPicker[data-placement^='right'] {
padding-top: 0 !important;
}
.ColorPickerPopover {
border-radius: 3px;
}
.ColorPickerPopover--light {
color: black;
background: linear-gradient(180deg, #ffffff 0%, #f7f8fa 104.25%);
box-shadow: 0px 2px 4px #dde4ed, 0px 0px 2px #dde4ed;
}
.ColorPickerPopover--dark {
color: #d8d9da;
background: linear-gradient(180deg, #1e2028 0%, #161719 104.25%);
box-shadow: 0px 2px 4px #000000, 0px 0px 2px #000000;
.ColorPickerPopover__tab {
background: #303133;
color: white;
cursor: pointer;
}
.ColorPickerPopover__tab--active {
background: none;
}
}
.ColorPickerPopover__content {
width: 336px;
min-height: 184px;
padding: 24px;
}
.ColorPickerPopover__tabs {
display: flex;
width: 100%;
border-radius: 3px 3px 0 0;
overflow: hidden;
}
.ColorPickerPopover__tab {
width: 50%;
text-align: center;
padding: 8px 0;
background: #dde4ed;
}
.ColorPickerPopover__tab--active {
background: white;
}
.ColorPicker__axisSwitch {
width: 100%;
}
.ColorPicker__axisSwitchLabel {
display: flex;
flex-grow: 1;
}
.gf-color-picker__body {
padding-bottom: $arrowSize;
padding-left: 6px;
}
.drop-popover.gf-color-picker {
.drop-content {
width: 210px;
}
}
// TODO: Remove. This is a temporary solution until color picker popovers are used
// with Drop.js.
.drop-popover.drop-popover--transparent {
.drop-content {
border: none;
background: none;
padding: 0;
max-width: none;
&:before {
display: none;
}
}
}
@import 'ButtonCascader/ButtonCascader'; @import 'ButtonCascader/ButtonCascader';
@import 'ColorPicker/ColorPicker';
@import 'Drawer/Drawer'; @import 'Drawer/Drawer';
@import 'RefreshPicker/RefreshPicker'; @import 'RefreshPicker/RefreshPicker';
@import 'Forms/Legacy/Select/Select'; @import 'Forms/Legacy/Select/Select';
......
...@@ -71,3 +71,24 @@ $easing: cubic-bezier(0, 0, 0.265, 1); ...@@ -71,3 +71,24 @@ $easing: cubic-bezier(0, 0, 0.265, 1);
padding: 0; padding: 0;
} }
} }
.drop-popover.gf-color-picker {
.drop-content {
width: 210px;
}
}
// TODO: Remove. This is a temporary solution until color picker popovers are used
// with Drop.js.
.drop-popover.drop-popover--transparent {
.drop-content {
border: none;
background: none;
padding: 0;
max-width: none;
&:before {
display: none;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment