From 671a0759085b1590b2c80778e99a2173181bc3e6 Mon Sep 17 00:00:00 2001 From: Elizabet Oliveira Date: Thu, 5 Nov 2020 17:32:09 +0000 Subject: [PATCH] Add EuiColorPaletteDisplay (#3865) * Initial color palette display code * Palette display section and testing one color * Type gradient as default * Using spans for linear fixed gradient with stops * Adding examples and improving code * Adding tests * Adding rest to spread required props. Adding classNames. * Better examples * CL * Is new * Adding line break * Adding a bleed area for fixed palettes * Placing CL into master * Replacing divs with spans * Removing classname * Code improvements * Update src/components/color_picker/color_palette_display/_color_palette_display.scss Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> * Update src-docs/src/views/color_picker/color_palette_picker.js Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> * Fixing ESLint warning * Improving complex example * ESLint * Complex example title size * Complex example with column compressed * Importing color prop with prop loader * ESLint * New structure * Adding sizes * ESLint * Update src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx Co-authored-by: Greg Thompson * Update src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx Co-authored-by: Greg Thompson * Adding getFixedLinearGradient * Small fix in palette picker example * typescript help * Addressing PR review * CL Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> Co-authored-by: Greg Thompson --- CHANGELOG.md | 1 + .../color_picker/color_palette_display.js | 202 +++++++++++++++++ ...tte_picker.tsx => color_palette_picker.js} | 55 +++-- .../color_picker/color_picker_example.js | 101 ++++++++- src/components/color_picker/_index.scss | 3 +- .../color_palette_display.test.tsx.snap | 214 ++++++++++++++++++ .../_color_palette_display.scss | 18 ++ .../_color_palette_display_fixed.scss | 12 + .../color_palette_display/_index.scss | 3 + .../color_palette_display/_variables.scss | 6 + .../color_palette_display.test.tsx | 139 ++++++++++++ .../color_palette_display.tsx | 102 +++++++++ .../color_palette_display_fixed.tsx | 55 +++++ .../color_palette_display_gradient.tsx | 38 ++++ .../color_palette_display/index.ts | 33 +++ .../color_palette_picker.test.tsx.snap | 122 ++++++++-- .../_color_palette_picker.scss | 9 +- .../color_palette_picker/_index.scss | 2 +- .../color_palette_picker.tsx | 38 ++-- .../color_picker/color_stops/color_stops.tsx | 3 + src/components/color_picker/index.ts | 2 + src/components/color_picker/utils.ts | 99 +++++--- src/components/index.js | 4 +- 23 files changed, 1145 insertions(+), 116 deletions(-) create mode 100644 src-docs/src/views/color_picker/color_palette_display.js rename src-docs/src/views/color_picker/{color_palette_picker.tsx => color_palette_picker.js} (77%) create mode 100644 src/components/color_picker/color_palette_display/__snapshots__/color_palette_display.test.tsx.snap create mode 100644 src/components/color_picker/color_palette_display/_color_palette_display.scss create mode 100644 src/components/color_picker/color_palette_display/_color_palette_display_fixed.scss create mode 100644 src/components/color_picker/color_palette_display/_index.scss create mode 100644 src/components/color_picker/color_palette_display/_variables.scss create mode 100644 src/components/color_picker/color_palette_display/color_palette_display.test.tsx create mode 100644 src/components/color_picker/color_palette_display/color_palette_display.tsx create mode 100644 src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx create mode 100644 src/components/color_picker/color_palette_display/color_palette_display_gradient.tsx create mode 100644 src/components/color_picker/color_palette_display/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 413fdc12109..d7464b88ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [`master`](https://github.com/elastic/eui/tree/master) +- Added `EuiColorPaletteDisplay` component ([#3865](https://github.com/elastic/eui/pull/3865)) - Added `initialFocusedItemIndex` support to `EuiContextMenuPanelDescriptor` ([#4223](https://github.com/elastic/eui/pull/4223)) **Bug fixes** diff --git a/src-docs/src/views/color_picker/color_palette_display.js b/src-docs/src/views/color_picker/color_palette_display.js new file mode 100644 index 00000000000..5ab59ab0b93 --- /dev/null +++ b/src-docs/src/views/color_picker/color_palette_display.js @@ -0,0 +1,202 @@ +import React, { useState } from 'react'; +import { + euiPaletteColorBlind, + euiPaletteForStatus, + euiPaletteForTemperature, + euiPaletteComplimentary, + euiPaletteNegative, + euiPalettePositive, + euiPaletteCool, + euiPaletteWarm, + euiPaletteGray, +} from '../../../../src/services/color'; + +import { + EuiColorPaletteDisplay, + EuiColorPalettePicker, + EuiFormRow, + EuiSpacer, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiRange, + EuiSwitch, + EuiCode, + EuiButtonEmpty, + EuiSelect, +} from '../../../../src/components/'; + +const paletteWithStops = [ + { + stop: 100, + color: 'white', + }, + { + stop: 250, + color: 'lightgray', + }, + { + stop: 320, + color: 'gray', + }, + { + stop: 470, + color: 'black', + }, +]; + +const paletteData = { + euiPaletteForStatus, + euiPaletteForTemperature, + euiPaletteComplimentary, + euiPaletteNegative, + euiPalettePositive, + euiPaletteCool, + euiPaletteWarm, + euiPaletteGray, +}; + +const paletteNames = Object.keys(paletteData); + +const sizes = [ + { value: 'xs', text: 'Extra small' }, + { value: 's', text: 'Small' }, + { value: 'm', text: 'Medium' }, +]; + +export default () => { + const [palette, setPalette] = useState('1'); + const [categories, setCategories] = useState(5); + const [selectionType, setSelectionType] = useState(true); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const [size, setSize] = useState(sizes[1].value); + + const onChangeSize = (e) => { + setSize(e.target.value); + }; + + const onChange = (e) => { + setCategories(parseInt(e.target.value)); + }; + + const palettes = paletteNames.map((paletteName, index) => { + return { + value: String(index + 1), + title: paletteName, + palette: paletteData[paletteNames[index]](categories), + type: selectionType ? 'fixed' : 'gradient', + }; + }); + + const selectedPalette = paletteData[paletteNames[palette - 1]](categories); + + const onButtonClick = () => + setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen); + const closePopover = () => setIsPopoverOpen(false); + + const button = ( + + Customize + + ); + + return ( + <> + +

Fixed

+
+ + + + +

Gradient

+
+ + + + +

Fixed with stops

+
+ + + + +

Gradient with stops

+
+ + + + +

Complex example

+
+ + + + + + + + + + + + + + + onChangeSize(e)} + compressed + /> + + + Display fixed + + } + display="columnCompressedSwitch"> + setSelectionType(!selectionType)} + compressed + /> + + + + + + ); +}; diff --git a/src-docs/src/views/color_picker/color_palette_picker.tsx b/src-docs/src/views/color_picker/color_palette_picker.js similarity index 77% rename from src-docs/src/views/color_picker/color_palette_picker.tsx rename to src-docs/src/views/color_picker/color_palette_picker.js index c60db2802a4..471f80ca085 100644 --- a/src-docs/src/views/color_picker/color_palette_picker.tsx +++ b/src-docs/src/views/color_picker/color_palette_picker.js @@ -4,17 +4,17 @@ import { euiPaletteForStatus, euiPaletteForTemperature, } from '../../../../src/services'; -import { EuiSwitch } from '../../../../src/components/form'; -import { EuiSpacer } from '../../../../src/components/spacer'; -import { EuiCode } from '../../../../src/components/code'; + import { + EuiSwitch, + EuiSpacer, + EuiCode, EuiColorPalettePicker, - EuiColorPalettePickerPaletteProps, -} from '../../../../src/components/color_picker/color_palette_picker'; -// @ts-ignore importing from a JS file +} from '../../../../src/components/'; + import { DisplayToggles } from '../form_controls/display_toggles'; -const palettes: EuiColorPalettePickerPaletteProps[] = [ +const palettes = [ { value: 'pallette_1', title: 'EUI color blind (fixed)', @@ -23,12 +23,18 @@ const palettes: EuiColorPalettePickerPaletteProps[] = [ }, { value: 'pallette_2', + title: 'EUI palette for status (gradient)', + palette: euiPaletteForStatus(5), + type: 'gradient', + }, + { + value: 'pallette_3', title: 'EUI palette for temperature (fixed)', palette: euiPaletteForTemperature(5), type: 'fixed', }, { - value: 'pallette_3', + value: 'pallette_4', title: 'Grayscale (gradient with stops)', palette: [ { @@ -37,11 +43,11 @@ const palettes: EuiColorPalettePickerPaletteProps[] = [ }, { stop: 250, - color: 'gray', + color: 'lightgray', }, { - stop: 350, - color: 'dimgray', + stop: 320, + color: 'gray', }, { stop: 470, @@ -51,10 +57,27 @@ const palettes: EuiColorPalettePickerPaletteProps[] = [ type: 'gradient', }, { - value: 'pallette_4', - title: 'EUI palette for status (gradient)', - palette: euiPaletteForStatus(5), - type: 'gradient', + value: 'pallette_5', + title: 'Grayscale (fixed with stops)', + palette: [ + { + stop: 100, + color: 'white', + }, + { + stop: 250, + color: 'lightgray', + }, + { + stop: 320, + color: 'gray', + }, + { + stop: 470, + color: 'black', + }, + ], + type: 'fixed', }, { value: 'custom', @@ -63,7 +86,7 @@ const palettes: EuiColorPalettePickerPaletteProps[] = [ }, ]; -export const ColorPalettePicker = () => { +export default () => { const [selectionDisplay, setSelectionDisplay] = useState(false); const [pallette, setPallette] = useState('pallette_1'); diff --git a/src-docs/src/views/color_picker/color_picker_example.js b/src-docs/src/views/color_picker/color_picker_example.js index dec75c6ad1c..28a27a2a5d3 100644 --- a/src-docs/src/views/color_picker/color_picker_example.js +++ b/src-docs/src/views/color_picker/color_picker_example.js @@ -1,4 +1,5 @@ import React from 'react'; +import { Link } from 'react-router-dom'; import { renderToHtml } from '../../services'; @@ -7,6 +8,7 @@ import { GuideSectionTypes } from '../../components'; import { EuiCode, EuiColorPicker, + EuiColorPaletteDisplay, EuiColorPalettePicker, EuiColorStops, EuiSpacer, @@ -18,6 +20,8 @@ import { EuiColorPalettePickerPaletteGradientProps, } from '!!prop-loader!../../../../src/components/color_picker/color_palette_picker/color_palette_picker'; +import { ColorStop } from '!!prop-loader!../../../../src/components/color_picker/color_stops/color_stop_thumb'; + import playgrounds from './playground'; import ColorPicker from './color_picker'; @@ -31,7 +35,34 @@ const colorPickerSnippet = ` `; -import { ColorPalettePicker } from './color_palette_picker'; +import ColorPaletteDisplay from './color_palette_display'; +const colorPaletteDisplaySource = require('!!raw-loader!./color_palette_display'); +const colorPaletteDisplayHtml = renderToHtml(ColorPaletteDisplay); +const colorPaletteDisplaySnippet = [ + ` +`, + ` +`, +]; + +import ColorPalettePicker from './color_palette_picker'; const colorPalettePickerSource = require('!!raw-loader!./color_palette_picker'); const colorPalettePickerHtml = renderToHtml(ColorPalettePicker); const colorPalettePickerSnippet = `

Use the palettes prop to pass your palettes as - an array of objects. For each object, you should pass a palette - (array of hex values) and specify the type. Use{' '} - fixed palettes for categorical data and{' '} - gradient palettes for continuous data. + an array strings or an array of{' '} + ColorStops in the form of{' '} + {'{ stop: number, color: string }'}. For each + object, you should pass a palette (array of hex values) and + specify the type. Use fixed{' '} + palettes for categorical data and gradient{' '} + palettes for continuous data.

@@ -363,10 +397,56 @@ export const ColorPickerExample = { EuiColorPalettePickerPaletteTextProps, EuiColorPalettePickerPaletteFixedProps, EuiColorPalettePickerPaletteGradientProps, + ColorStop, }, snippet: colorPalettePickerSnippet, demo: , }, + { + title: 'Color palette display', + text: ( + + +

+ Use EuiColorPaletteDisplay to show the palette in + use for a data visualization. +

+

+ Use the palette prop to pass your palette as an array of color{' '} + strings or an array of{' '} + ColorStops in the form of{' '} + {'{ stop: number, color: string }'}. Use{' '} + fixed palettes for categorical data and{' '} + gradient palettes for continuous data. +

+

+ In cases you need to apply a palette, it's recommended to use + the{' '} + + EuiColorPalettePicker + + . +

+
+
+ ), + source: [ + { + type: GuideSectionTypes.JS, + code: colorPaletteDisplaySource, + }, + { + type: GuideSectionTypes.HTML, + code: colorPaletteDisplayHtml, + }, + ], + props: { + EuiColorPaletteDisplay, + ColorStop, + }, + snippet: colorPaletteDisplaySnippet, + demo: , + }, { title: 'Color stops', text: ( @@ -391,7 +471,10 @@ export const ColorPickerExample = { code: colorStopsHtml, }, ], - props: { EuiColorStops }, + props: { + EuiColorStops, + ColorStop, + }, snippet: [ colorStopsSnippetStandard, colorStopsSnippetAdd, @@ -409,9 +492,9 @@ export const ColorPickerExample = { defined min and max range values. It is also possible to leave the range open-ended for cases where the target data set is unknown or maleable. In this - case, a user{"'"}s added values will define min{' '} - and max and users will have more freedom over - resetting the values on the fly. + case, a user's added values will define{' '} + min and max and users will + have more freedom over resetting the values on the fly.

diff --git a/src/components/color_picker/_index.scss b/src/components/color_picker/_index.scss index cd7341001db..895912e9bc9 100644 --- a/src/components/color_picker/_index.scss +++ b/src/components/color_picker/_index.scss @@ -4,4 +4,5 @@ @import 'hue'; @import 'saturation'; @import 'color_stops/index'; -@import 'color_palette_picker/index'; \ No newline at end of file +@import 'color_palette_picker/index'; +@import 'color_palette_display/index'; \ No newline at end of file diff --git a/src/components/color_picker/color_palette_display/__snapshots__/color_palette_display.test.tsx.snap b/src/components/color_picker/color_palette_display/__snapshots__/color_palette_display.test.tsx.snap new file mode 100644 index 00000000000..9874be69b8c --- /dev/null +++ b/src/components/color_picker/color_palette_display/__snapshots__/color_palette_display.test.tsx.snap @@ -0,0 +1,214 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EuiColorPaletteDisplay is rendered 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props HTML attributes accepts span attributes 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props size m is rendered 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props size s is rendered 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props size xs is rendered 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props type and palette are rendered with type fixed and palette with stops 1`] = ` + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props type and palette are rendered with type fixed and palette without stops 1`] = ` + + + + + + + + + +`; + +exports[`EuiColorPaletteDisplay props type and palette are rendered with type gradient and palette with stops 1`] = ` + +`; + +exports[`EuiColorPaletteDisplay props type and palette are rendered with type gradient and palette without stops 1`] = ` + +`; diff --git a/src/components/color_picker/color_palette_display/_color_palette_display.scss b/src/components/color_picker/color_palette_display/_color_palette_display.scss new file mode 100644 index 00000000000..bfc2a1e8a48 --- /dev/null +++ b/src/components/color_picker/color_palette_display/_color_palette_display.scss @@ -0,0 +1,18 @@ +.euiColorPaletteDisplay { + display: flex; + flex-direction: row; + overflow: hidden; + height: $euiSizeS; +} + +@each $name, $size in $euiColorPaletteDisplaySizes { + .euiColorPaletteDisplay--#{$name} { + @include innerBorder('dark', $size, .2); + height: $size; + border-radius: $size; + } + + .euiColorPaletteDisplay--#{$name} .euiColorPaletteDisplayFixed__bleedArea { + height: $size; + } +} diff --git a/src/components/color_picker/color_palette_display/_color_palette_display_fixed.scss b/src/components/color_picker/color_palette_display/_color_palette_display_fixed.scss new file mode 100644 index 00000000000..f39a743f052 --- /dev/null +++ b/src/components/color_picker/color_palette_display/_color_palette_display_fixed.scss @@ -0,0 +1,12 @@ +.euiColorPaletteDisplayFixed { + // In a few screen sizes the palette display doesn't get a fully 100% width + // it gets 1px less on width and for this reason we're adding an horizontal 1px bleed area + &__bleedArea { + position: absolute; + top: 0; + left: 0; + display: flex; + height: $euiSizeS; + width: calc(100% + 1px); + } +} diff --git a/src/components/color_picker/color_palette_display/_index.scss b/src/components/color_picker/color_palette_display/_index.scss new file mode 100644 index 00000000000..fd1e1d6846d --- /dev/null +++ b/src/components/color_picker/color_palette_display/_index.scss @@ -0,0 +1,3 @@ +@import 'variables'; +@import 'color_palette_display'; +@import 'color_palette_display_fixed'; diff --git a/src/components/color_picker/color_palette_display/_variables.scss b/src/components/color_picker/color_palette_display/_variables.scss new file mode 100644 index 00000000000..96c9024c891 --- /dev/null +++ b/src/components/color_picker/color_palette_display/_variables.scss @@ -0,0 +1,6 @@ +// Color Palette Display come in different sizes. +$euiColorPaletteDisplaySizes: ( + sizeExtraSmall: $euiSizeXS, + sizeSmall: $euiSizeS, + sizeMedium: $euiSize, +); diff --git a/src/components/color_picker/color_palette_display/color_palette_display.test.tsx b/src/components/color_picker/color_palette_display/color_palette_display.test.tsx new file mode 100644 index 00000000000..74ea700aa5b --- /dev/null +++ b/src/components/color_picker/color_palette_display/color_palette_display.test.tsx @@ -0,0 +1,139 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { render } from 'enzyme'; + +import { EuiColorPaletteDisplay, SIZES } from './color_palette_display'; +import { requiredProps } from '../../../test'; + +const palette = ['#1fb0b2', '#ffdb6d', '#ee9191', '#ffffff', '#888094']; + +const paletteWithStops = [ + { + stop: 100, + color: '#54B399', + }, + { + stop: 250, + color: '#D36086', + }, + { + stop: 350, + color: '#9170B8', + }, + { + stop: 470, + color: '#F5A700', + }, +]; + +describe('EuiColorPaletteDisplay', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + describe('props', () => { + describe('type and palette', () => { + it('are rendered with type fixed and palette without stops', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + it('are rendered with type gradient and palette without stops', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + it('are rendered with type fixed and palette with stops', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + + it('are rendered with type gradient and palette with stops', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('size', () => { + SIZES.forEach((size) => { + it(`${size} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('HTML attributes', () => { + it('accepts span attributes', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/src/components/color_picker/color_palette_display/color_palette_display.tsx b/src/components/color_picker/color_palette_display/color_palette_display.tsx new file mode 100644 index 00000000000..6dae05d5795 --- /dev/null +++ b/src/components/color_picker/color_palette_display/color_palette_display.tsx @@ -0,0 +1,102 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FunctionComponent } from 'react'; +import classnames from 'classnames'; +import { ExclusiveUnion, keysOf } from '../../common'; +import { ColorStop } from '../color_stops'; +import { + EuiColorPaletteDisplayFixed, + EuiColorPaletteDisplayFixedProps, +} from './color_palette_display_fixed'; +import { + EuiColorPaletteDisplayGradient, + EuiColorPaletteDisplayGradientProps, +} from './color_palette_display_gradient'; + +const sizeToClassNameMap = { + xs: 'euiColorPaletteDisplay--sizeExtraSmall', + s: 'euiColorPaletteDisplay--sizeSmall', + m: 'euiColorPaletteDisplay--sizeMedium', +}; + +export const SIZES = keysOf(sizeToClassNameMap); + +export type EuiColorPaletteDisplaySize = keyof typeof sizeToClassNameMap; + +export interface EuiColorPaletteDisplayShared { + /** + * Array of color `strings` or an array of #ColorStop. The stops must be numbers in an ordered range. + */ + palette: string[] | ColorStop[]; +} + +interface DisplayGradient extends EuiColorPaletteDisplayGradientProps { + /** + * Specify the type of palette. + * `gradient`: each color fades into the next. + */ + type: 'gradient'; +} + +interface DisplayFixed extends EuiColorPaletteDisplayFixedProps { + /** + * `fixed`: individual color blocks. + */ + type?: 'fixed'; +} + +export type EuiColorPaletteDisplayProps = { + /** + * Height of the palette display + */ + size?: EuiColorPaletteDisplaySize; +} & ExclusiveUnion; + +export const EuiColorPaletteDisplay: FunctionComponent = ({ + type = 'fixed', + palette, + className, + size = 's', + ...rest +}) => { + const classes = classnames( + 'euiColorPaletteDisplay', + className, + sizeToClassNameMap[size] + ); + + return ( + <> + {type === 'fixed' ? ( + + ) : ( + + )} + + ); +}; diff --git a/src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx b/src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx new file mode 100644 index 00000000000..a9e8930abaa --- /dev/null +++ b/src/components/color_picker/color_palette_display/color_palette_display_fixed.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FunctionComponent, HTMLAttributes } from 'react'; +import { CommonProps } from '../../common'; +import { getFixedLinearGradient } from '../utils'; +import { EuiColorPaletteDisplayShared } from './color_palette_display'; + +export interface EuiColorPaletteDisplayFixedProps + extends HTMLAttributes, + CommonProps, + EuiColorPaletteDisplayShared {} + +interface paletteItem { + color: string; + width: string; +} + +export const EuiColorPaletteDisplayFixed: FunctionComponent = ({ + palette, + ...rest +}) => { + const fixedGradient = getFixedLinearGradient(palette); + + const paletteStops = fixedGradient.map((item: paletteItem, index: number) => ( + + )); + + return ( + + + {paletteStops} + + + ); +}; diff --git a/src/components/color_picker/color_palette_display/color_palette_display_gradient.tsx b/src/components/color_picker/color_palette_display/color_palette_display_gradient.tsx new file mode 100644 index 00000000000..7c148b1d162 --- /dev/null +++ b/src/components/color_picker/color_palette_display/color_palette_display_gradient.tsx @@ -0,0 +1,38 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { FunctionComponent, HTMLAttributes } from 'react'; +import { CommonProps } from '../../common'; +import { getLinearGradient } from '../utils'; +import { EuiColorPaletteDisplayShared } from './color_palette_display'; + +export interface EuiColorPaletteDisplayGradientProps + extends HTMLAttributes, + CommonProps, + EuiColorPaletteDisplayShared {} + +export const EuiColorPaletteDisplayGradient: FunctionComponent = ({ + palette, + style = {}, + ...rest +}) => { + const gradient = getLinearGradient(palette); + + return ; +}; diff --git a/src/components/color_picker/color_palette_display/index.ts b/src/components/color_picker/color_palette_display/index.ts new file mode 100644 index 00000000000..8c3f953d8c2 --- /dev/null +++ b/src/components/color_picker/color_palette_display/index.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { + EuiColorPaletteDisplay, + EuiColorPaletteDisplayProps, +} from './color_palette_display'; + +export { + EuiColorPaletteDisplayFixed, + EuiColorPaletteDisplayFixedProps, +} from './color_palette_display_fixed'; + +export { + EuiColorPaletteDisplayGradient, + EuiColorPaletteDisplayGradientProps, +} from './color_palette_display_gradient'; diff --git a/src/components/color_picker/color_palette_picker/__snapshots__/color_palette_picker.test.tsx.snap b/src/components/color_picker/color_palette_picker/__snapshots__/color_palette_picker.test.tsx.snap index bbddf2aec64..28804ea3f8a 100644 --- a/src/components/color_picker/color_palette_picker/__snapshots__/color_palette_picker.test.tsx.snap +++ b/src/components/color_picker/color_palette_picker/__snapshots__/color_palette_picker.test.tsx.snap @@ -124,10 +124,29 @@ exports[`EuiColorPalettePicker is rendered with a selected fixed palette 1`] = ` id="generated-id" > Select an option: -
+ + + + + + + + + , is selected
Select an option: -
, is selected @@ -198,8 +236,8 @@ exports[`EuiColorPalettePicker is rendered with a selected gradient palette 1`] data-test-subj="test subject string" type="button" > -
@@ -244,8 +282,8 @@ exports[`EuiColorPalettePicker is rendered with a selected gradient palette with id="generated-id" > Select an option: -
, is selected @@ -258,8 +296,8 @@ exports[`EuiColorPalettePicker is rendered with a selected gradient palette with data-test-subj="test subject string" type="button" > -
@@ -356,9 +394,29 @@ exports[`EuiColorPalettePicker more props are propagated to each option 1`] = ` id="generated-id" > Select an option: -
+ + + + + + + + + , is selected
{ - const getPalette = ( - item: - | EuiColorPalettePickerPaletteFixedProps - | EuiColorPalettePickerPaletteGradientProps - ) => { - const background = - item.type === 'fixed' - ? getFixedLinearGradient(item.palette) - : getLinearGradient(item.palette); - - return ( -
+ const getPalette = ({ + type, + palette, + }: + | EuiColorPalettePickerPaletteFixedProps + | EuiColorPalettePickerPaletteGradientProps) => { + // Working around ExclusiveUnion + return type === 'gradient' ? ( + + ) : ( + ); }; diff --git a/src/components/color_picker/color_stops/color_stops.tsx b/src/components/color_picker/color_stops/color_stops.tsx index 25b1c7f7cf9..a2482a7c958 100644 --- a/src/components/color_picker/color_stops/color_stops.tsx +++ b/src/components/color_picker/color_stops/color_stops.tsx @@ -48,6 +48,9 @@ import { EuiRangeWrapper } from '../../form/range/range_wrapper'; export interface EuiColorStopsProps extends CommonProps { addColor?: ColorStop['color']; + /** + * An array of #ColorStop. The stops must be numbers in an ordered range. + */ colorStops: ColorStop[]; onChange: (stops?: ColorStop[], isInvalid?: boolean) => void; fullWidth?: boolean; diff --git a/src/components/color_picker/index.ts b/src/components/color_picker/index.ts index 6d38e67bfdf..405fe399c2a 100644 --- a/src/components/color_picker/index.ts +++ b/src/components/color_picker/index.ts @@ -27,3 +27,5 @@ export { EuiColorPalettePickerProps, EuiColorPalettePickerPaletteProps, } from './color_palette_picker'; + +export { EuiColorPaletteDisplay } from './color_palette_display'; diff --git a/src/components/color_picker/utils.ts b/src/components/color_picker/utils.ts index e214ee619e0..40bac3cb091 100644 --- a/src/components/color_picker/utils.ts +++ b/src/components/color_picker/utils.ts @@ -161,7 +161,7 @@ export const getChromaColor = (input?: string | null, allowOpacity = false) => { // Given an array of objects with key value pairs stop/color returns a css linear-gradient // Or given an array of hex colors returns a css linear-gradient export const getLinearGradient = (palette: string[] | ColorStop[]) => { - const intervals = palette.length; + const lastColorStopArrayPosition = palette.length - 1; let linearGradient; @@ -174,58 +174,87 @@ export const getLinearGradient = (palette: string[] | ColorStop[]) => { linearGradient = `linear-gradient(to right, ${paletteColorStop[0].color} 0%,`; - const decimal = 100 / paletteColorStop[paletteColorStop.length - 1].stop; + const lastColorStopDecimal = + 100 / paletteColorStop[lastColorStopArrayPosition].stop; - for (let i = 1; i < intervals - 1; i++) { + for (let i = 1; i < lastColorStopArrayPosition; i++) { linearGradient = `${linearGradient} ${ paletteColorStop[i].color - }\ ${Math.floor(paletteColorStop[i].stop * decimal)}%,`; + }\ ${Math.floor(paletteColorStop[i].stop * lastColorStopDecimal)}%,`; } - const linearGradientStyle = `${linearGradient} ${ - paletteColorStop[palette.length - 1].color - } 100%)`; + const linearGradientStyle = `${linearGradient} ${paletteColorStop[lastColorStopArrayPosition].color} 100%)`; return linearGradientStyle; } else { linearGradient = `linear-gradient(to right, ${palette[0]} 0%,`; - for (let i = 1; i < intervals - 1; i++) { + for (let i = 1; i < lastColorStopArrayPosition; i++) { linearGradient = `${linearGradient} ${palette[i]}\ ${Math.floor( - (100 * i) / (intervals - 1) + (100 * i) / lastColorStopArrayPosition )}%,`; } - const linearGradientStyle = `${linearGradient} ${ - palette[palette.length - 1] - } 100%)`; + const linearGradientStyle = `${linearGradient} ${palette[lastColorStopArrayPosition]} 100%)`; return linearGradientStyle; } }; -// Given an array of hex colors returns a css linear-gradient with individual color blocks -export const getFixedLinearGradient = (palette: string[]) => { - const intervals = palette.length; - - let fixedLinearGradient; - - for (let i = 0; i < intervals; i++) { - const initialColorStop = `${palette[0]} 0%, ${palette[0]}\ ${Math.floor( - (100 * 1) / intervals - )}%`; - const colorStop = `${palette[i]}\ ${Math.floor((100 * i) / intervals)}%, ${ - palette[i] - }\ ${Math.floor((100 * (i + 1)) / intervals)}%`; - - if (i === 0) { - fixedLinearGradient = `linear-gradient(to right, ${initialColorStop},`; - } else if (i === palette.length - 1) { - fixedLinearGradient = `${fixedLinearGradient} ${colorStop})`; - } else { - fixedLinearGradient = `${fixedLinearGradient} ${colorStop},`; - } - } +// Given an array of objects with key value pairs stop/color or an array of hex colors +// returns an array of objects with key value pairs color/width +export const getFixedLinearGradient = (palette: string[] | ColorStop[]) => { + const paletteHasStops = palette.some((item: string | ColorStop) => { + return typeof item === 'object'; + }); + + if (paletteHasStops) { + const paletteColorStop = palette as ColorStop[]; + + const fixedLinearGradientWithStops = paletteColorStop.map( + (colorStop: ColorStop, index: number) => { + const lastColorStopArrayPosition = palette.length - 1; + + const lastColorStopDecimal = + 100 / paletteColorStop[lastColorStopArrayPosition].stop; + + const isFirstColorStop = index === 0; - return fixedLinearGradient; + let previousColorStopWidth; + + if (isFirstColorStop) { + previousColorStopWidth = 0; + } else { + previousColorStopWidth = Math.floor( + paletteColorStop[index - 1].stop * lastColorStopDecimal + ); + } + + const currentColorStopWidth = Math.floor( + colorStop.stop * lastColorStopDecimal + ); + + const colorStopWidth = currentColorStopWidth - previousColorStopWidth; + + return { + color: colorStop.color, + width: `${colorStopWidth}%`, + }; + } + ); + + return fixedLinearGradientWithStops; + } else { + const paletteColorStop = palette as string[]; + const paletteWidth = 100 / palette.length; + + const fixedLinearGradientWidthAuto = paletteColorStop.map( + (hexCode: string) => ({ + color: hexCode, + width: `${paletteWidth}%`, + }) + ); + + return fixedLinearGradientWidthAuto; + } }; diff --git a/src/components/index.js b/src/components/index.js index 1f162c4c4f6..3941536a3f5 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -60,6 +60,8 @@ export { EuiCodeEditor } from './code_editor'; export { EuiCollapsibleNav, EuiCollapsibleNavGroup } from './collapsible_nav'; export { + EuiColorPalettePicker, + EuiColorPaletteDisplay, EuiColorPicker, EuiColorPickerSwatch, EuiColorStops, @@ -67,8 +69,6 @@ export { EuiSaturation, } from './color_picker'; -export { EuiColorPalettePicker } from './color_picker/color_palette_picker'; - export { EuiComboBox } from './combo_box'; export { EuiComment, EuiCommentList } from './comment_list';