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 2a997acec0c..b349fb8a644 100644 --- a/src-docs/src/views/color_picker/color_picker_example.js +++ b/src-docs/src/views/color_picker/color_picker_example.js @@ -9,8 +9,6 @@ import { EuiColorPaletteDisplay, EuiColorPalettePicker, EuiText, - EuiCallOut, - EuiLink, } from '../../../../src/components'; import { EuiColorPalettePickerPaletteTextProps, @@ -327,32 +325,6 @@ export const ColorPickerExample = { snippet: colorPaletteDisplaySnippet, demo: , }, - { - title: 'Color stops', - isDeprecated: true, - text: ( - -

- EuiColorStops is being deprecated due to low usage - and high maintenance requirements. -

-

- If necessary, we recommend{' '} - - copying the component to your application - - . The component will be permanently removed in October 2023. -

-
- ), - }, { title: 'Format selection', source: [ diff --git a/src/components/color_picker/color_stops/__snapshots__/color_stop_thumb.test.tsx.snap b/src/components/color_picker/color_stops/__snapshots__/color_stop_thumb.test.tsx.snap deleted file mode 100644 index 964ccb2355d..00000000000 --- a/src/components/color_picker/color_stops/__snapshots__/color_stop_thumb.test.tsx.snap +++ /dev/null @@ -1,137 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders EuiColorStopThumb 1`] = ` -
-
-
-
-`; - -exports[`renders disabled EuiColorStopThumb 1`] = ` -
-
-
-
-`; - -exports[`renders picker-only EuiColorStopThumb 1`] = ` -
-
-
-
-`; - -exports[`renders readOnly EuiColorStopThumb 1`] = ` -
-
-
-
-`; - -exports[`renders swatch-only EuiColorStopThumb 1`] = ` -
-
-
-
-`; diff --git a/src/components/color_picker/color_stops/__snapshots__/color_stops.test.tsx.snap b/src/components/color_picker/color_stops/__snapshots__/color_stops.test.tsx.snap deleted file mode 100644 index f1b0ec7b47d..00000000000 --- a/src/components/color_picker/color_stops/__snapshots__/color_stops.test.tsx.snap +++ /dev/null @@ -1,834 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`renders compressed EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`renders disabled EuiColorStops 1`] = ` -
-

- Test: Disabled. Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`renders empty EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-`; - -exports[`renders fixed stop EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`renders free-range EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-`; - -exports[`renders fullWidth EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[`renders max-only EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-`; - -exports[`renders min-only EuiColorStops 1`] = ` -
-

- Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-`; - -exports[`renders readOnly EuiColorStops 1`] = ` -
-

- Test: Read-only. Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop. -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/src/components/color_picker/color_stops/color_stop_thumb.styles.ts b/src/components/color_picker/color_stops/color_stop_thumb.styles.ts deleted file mode 100644 index 1dea78f03d2..00000000000 --- a/src/components/color_picker/color_stops/color_stop_thumb.styles.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { css } from '@emotion/react'; - -import { UseEuiTheme } from '../../../services'; -import { mathWithUnits } from '../../../global_styling'; -import { - euiRangeVariables, - euiRangeThumbFocus, -} from '../../form/range/range.styles'; -import { euiColorPickerVariables } from '../color_picker.styles'; - -export const euiColorStopThumbStyles = (euiThemeContext: UseEuiTheme) => { - return { - // Base - euiColorStopThumb: css` - &:not(:disabled) { - inset-block-start: 0; - margin-block-start: 0; - pointer-events: auto; - cursor: grab; - - &:active { - cursor: grabbing; - } - } - `, - isPopoverOpen: css` - ${euiRangeThumbFocus(euiThemeContext)} - `, - }; -}; - -export const euiColorStopThumbPopoverStyles = ( - euiThemeContext: UseEuiTheme -) => { - const range = euiRangeVariables(euiThemeContext); - const { euiTheme } = euiThemeContext; - - return { - // Base - euiColorStopThumbPopover: css` - position: absolute; - inset-block-start: 50%; - inline-size: ${range.thumbWidth}; - block-size: ${range.thumbHeight}; - margin-block-start: ${mathWithUnits(range.thumbHeight, (x) => x * -0.5)}; - - .euiColorStopThumbPopover__anchor { - position: absolute; - inline-size: 100%; - block-size: 100%; - - /* Background color can potentially have opacity - Pseudo element placed below the thumb to prevent the track from showing through */ - &::before { - content: ''; - display: block; - position: absolute; - inset-inline-start: 0; - inset-block-start: 0; - block-size: ${range.thumbHeight}; - inline-size: ${range.thumbWidth}; - border-radius: ${range.thumbHeight}; - background: ${euiTheme.colors.emptyShade}; - } - } - `, - isLoadingPanel: css` - /* Overrides a stateful class on EuiPopover -> EuiPanel */ - visibility: hidden !important; /* stylelint-disable-line declaration-no-important */ - `, - hasFocus: css` - z-index: ${range.thumbZIndex}; - `, - }; -}; - -export const euiColorStopStyles = (euiThemeContext: UseEuiTheme) => { - const colorPicker = euiColorPickerVariables(euiThemeContext); - - return { - // Base - euiColorStop: css` - inline-size: ${colorPicker.width}; - `, - }; -}; diff --git a/src/components/color_picker/color_stops/color_stop_thumb.test.tsx b/src/components/color_picker/color_stops/color_stop_thumb.test.tsx deleted file mode 100644 index f32f2eba097..00000000000 --- a/src/components/color_picker/color_stops/color_stop_thumb.test.tsx +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; - -import { EuiColorStopThumb } from './color_stop_thumb'; - -import { requiredProps } from '../../../test'; -import { shouldRenderCustomStyles } from '../../../test/internal'; -import { render } from '../../../test/rtl'; - -jest.mock('../../portal', () => ({ - EuiPortal: ({ children }: { children: any }) => children, -})); - -const onChange = jest.fn(); - -// Note: Unit/interaction tests can be found in ./color_stops.test - -shouldRenderCustomStyles( - {}} - closePopover={() => {}} - {...requiredProps} - />, - { childProps: ['valueInputProps'] } -); - -test('renders EuiColorStopThumb', () => { - const { container } = render( - {}} - closePopover={() => {}} - {...requiredProps} - /> - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders swatch-only EuiColorStopThumb', () => { - const { container } = render( - {}} - closePopover={() => {}} - {...requiredProps} - /> - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders picker-only EuiColorStopThumb', () => { - const { container } = render( - {}} - closePopover={() => {}} - {...requiredProps} - /> - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders disabled EuiColorStopThumb', () => { - const { container } = render( - {}} - closePopover={() => {}} - {...requiredProps} - /> - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders readOnly EuiColorStopThumb', () => { - const { container } = render( - {}} - closePopover={() => {}} - {...requiredProps} - /> - ); - expect(container.firstChild).toMatchSnapshot(); -}); diff --git a/src/components/color_picker/color_stops/color_stop_thumb.tsx b/src/components/color_picker/color_stops/color_stop_thumb.tsx deleted file mode 100644 index 271b0ab2aaa..00000000000 --- a/src/components/color_picker/color_stops/color_stop_thumb.tsx +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { - FunctionComponent, - CSSProperties, - ReactChild, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; -import classNames from 'classnames'; - -import { CommonProps } from '../../common'; -import { - getPositionFromStop, - getStopFromMouseLocation, - isColorInvalid, - isStopInvalid, -} from './utils'; -import { getChromaColor } from '../utils'; -import { keys, useMouseMove, useEuiTheme } from '../../../services'; - -import { EuiButtonIcon } from '../../button'; -import { EuiColorPicker, EuiColorPickerProps } from '../color_picker'; -import { EuiFlexGroup, EuiFlexItem } from '../../flex'; -import { EuiFieldNumber, EuiFieldNumberProps, EuiFormRow } from '../../form'; -import { EuiI18n } from '../../i18n'; -import { EuiPopover } from '../../popover'; -import { EuiScreenReaderOnly } from '../../accessibility'; -import { EuiSpacer } from '../../spacer'; -import { EuiRangeThumb } from '../../form/range/range_thumb'; - -import { - euiColorStopThumbStyles, - euiColorStopThumbPopoverStyles, - euiColorStopStyles, -} from './color_stop_thumb.styles'; - -export interface ColorStop { - stop: number; - color: string; -} - -interface EuiColorStopThumbProps extends CommonProps, ColorStop { - className?: string; - onChange: (colorStop: ColorStop) => void; - onFocus?: () => void; - onRemove?: () => void; - globalMin: number; - globalMax: number; - localMin: number; - localMax: number; - min?: number; - max?: number; - isRangeMin?: boolean; - isRangeMax?: boolean; - parentRef?: HTMLDivElement | null; - colorPickerMode: EuiColorPickerProps['mode']; - colorPickerShowAlpha?: EuiColorPickerProps['showAlpha']; - colorPickerSwatches?: EuiColorPickerProps['swatches']; - disabled?: boolean; - readOnly?: boolean; - isPopoverOpen: boolean; - openPopover: () => void; - closePopover: () => void; - 'data-index'?: string; - 'aria-valuetext'?: string; - style?: CSSProperties; - valueInputProps?: Partial; -} - -export const EuiColorStopThumb: FunctionComponent = ({ - className, - stop, - color, - onChange, - onFocus, - onRemove, - globalMin, - globalMax, - localMin, - localMax, - min, - max, - isRangeMin = false, - isRangeMax = false, - parentRef, - colorPickerMode, - colorPickerShowAlpha, - colorPickerSwatches, - disabled, - readOnly, - isPopoverOpen, - openPopover, - closePopover, - 'data-index': dataIndex, - 'aria-valuetext': ariaValueText, - style, - valueInputProps = {}, - ...rest -}) => { - const background = useMemo(() => { - const chromaColor = getChromaColor(color, colorPickerShowAlpha); - return chromaColor ? chromaColor.css() : undefined; - }, [color, colorPickerShowAlpha]); - const [hasFocus, setHasFocus] = useState(isPopoverOpen); - const [colorIsInvalid, setColorIsInvalid] = useState( - isColorInvalid(color, colorPickerShowAlpha) - ); - const [stopIsInvalid, setStopIsInvalid] = useState(isStopInvalid(stop)); - const [numberInputRef, setNumberInputRef] = useState( - null - ); - const popoverRef = useRef(null); - - useEffect(() => { - if (isPopoverOpen && popoverRef && popoverRef.current) { - popoverRef.current.positionPopoverFixed(); - } - }, [isPopoverOpen, stop]); - - const getStopFromMouseLocationFn = (location: { x: number; y: number }) => { - // Guard against `null` ref in usage - return getStopFromMouseLocation(location, parentRef!, globalMin, globalMax); - }; - - const getPositionFromStopFn = (stop: ColorStop['stop']) => { - // Guard against `null` ref in usage - return getPositionFromStop(stop, parentRef!, globalMin, globalMax); - }; - - const handleOnRemove = () => { - if (onRemove) { - closePopover(); - onRemove(); - } - }; - - const handleFocus = () => { - setHasFocus(true); - if (onFocus) { - onFocus(); - } - }; - - const setHasFocusTrue = () => setHasFocus(true); - const setHasFocusFalse = () => setHasFocus(false); - - const handleColorChange = (value: ColorStop['color']) => { - setColorIsInvalid(isColorInvalid(value, colorPickerShowAlpha)); - onChange({ stop, color: value }); - }; - - const handleStopChange = (value: ColorStop['stop']) => { - const willBeInvalid = value > localMax || value < localMin; - - if (willBeInvalid) { - if (value > localMax) { - value = localMax; - } - if (value < localMin) { - value = localMin; - } - } - setStopIsInvalid(isStopInvalid(value)); - onChange({ stop: value, color }); - }; - - const handleStopInputChange = (e: React.ChangeEvent) => { - let value = parseFloat(e.target.value); - - const willBeInvalid = value > globalMax || value < globalMin; - - if (willBeInvalid) { - if (value > globalMax && max != null) { - value = globalMax; - } - if (value < globalMin && min != null) { - value = globalMin; - } - } - - setStopIsInvalid(isStopInvalid(value)); - onChange({ stop: value, color }); - }; - - const handlePointerChange = ( - location: { x: number; y: number }, - isFirstInteraction?: boolean - ) => { - if (isFirstInteraction) return; // Prevents change on the initial MouseDown event - if (parentRef == null) { - return; - } - const newStop = getStopFromMouseLocationFn(location); - handleStopChange(newStop); - }; - - const handleKeyDown = (event: React.KeyboardEvent) => { - switch (event.key) { - case keys.ENTER: - event.preventDefault(); - openPopover(); - break; - - case keys.ARROW_LEFT: - event.preventDefault(); - if (readOnly) return; - handleStopChange(stop - 1); - break; - - case keys.ARROW_RIGHT: - event.preventDefault(); - if (readOnly) return; - handleStopChange(stop + 1); - break; - } - }; - - const [handleMouseDown, handleInteraction] = - useMouseMove(handlePointerChange); - - const handleOnMouseDown = (e: React.MouseEvent) => { - if (!readOnly) { - handleMouseDown(e); - } - openPopover(); - }; - - const handleTouchInteraction = (e: React.TouchEvent) => { - if (!readOnly) { - handleInteraction(e); - } - }; - - const handleTouchStart = (e: React.TouchEvent) => { - handleTouchInteraction(e); - if (!isPopoverOpen) { - openPopover(); - } - }; - - const euiTheme = useEuiTheme(); - - const popoverStyles = euiColorStopThumbPopoverStyles(euiTheme); - const cssPopoverStyles = [ - popoverStyles.euiColorStopThumbPopover, - (hasFocus || isPopoverOpen) && popoverStyles.hasFocus, - ]; - - const thumbStyles = euiColorStopThumbStyles(euiTheme); - const cssThumbStyles = [ - thumbStyles.euiColorStopThumb, - isPopoverOpen && thumbStyles.isPopoverOpen, - ]; - - const colorStopStyles = euiColorStopStyles(euiTheme); - const cssColorStopStyles = colorStopStyles.euiColorStop; - - const classes = classNames('euiColorStopPopover', className); - - return ( - - {([buttonAriaLabel, buttonTitle]: ReactChild[]) => { - const ariaLabel = buttonAriaLabel as string; - const title = buttonTitle as string; - return ( - - ); - }} - - } - > -
- -

- -

-
- - - - {([stopLabel, stopErrorMessage]: React.ReactChild[]) => ( - - - - )} - - - {!readOnly && ( - - - - {(removeLabel: string) => ( - - )} - - - - )} - - {!readOnly && } - -
-
- ); -}; diff --git a/src/components/color_picker/color_stops/color_stops.styles.ts b/src/components/color_picker/color_stops/color_stops.styles.ts deleted file mode 100644 index abf000a06e0..00000000000 --- a/src/components/color_picker/color_stops/color_stops.styles.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { css } from '@emotion/react'; - -import { UseEuiTheme, darken, brighten, hexToRgb } from '../../../services'; -import { mathWithUnits, euiCanAnimate } from '../../../global_styling'; -import { euiCustomControl } from '../../form/form.styles'; - -import { - euiRangeThumbStyle, - euiRangeVariables, -} from '../../form/range/range.styles'; - -export const euiColorStopsStyles = (euiThemeContext: UseEuiTheme) => { - const range = euiRangeVariables(euiThemeContext); - const { euiTheme, colorMode } = euiThemeContext; - - const isDarkMode = colorMode === 'DARK'; - const stripeColor = isDarkMode - ? brighten(range.trackColor, 0.5) - : darken(range.trackColor, 0.5); - const stripesBackground = `repeating-linear-gradient( - -45deg, - ${range.trackColor}, - ${range.trackColor} 25%, - ${stripeColor} 25%, - ${stripeColor} 50%, - ${range.trackColor} 50% - )`; - - return { - // Base - euiColorStops: css``, - isEnabled: css` - /* Show focus ring on keyboard focus only and not mouse click/drag */ - &:focus { - outline: none; - } - - &:focus-visible { - .euiColorStops__track::after { - box-shadow: 0 0 0 1px - rgba(${hexToRgb(euiTheme.colors.emptyShade).join(', ')}, 0.8), - 0 0 0 3px ${range.focusColor}; - } - } - `, - isDisabled: css``, - isHoverDisabled: css``, - isReadOnly: css``, - isDragging: css` - cursor: grabbing; - `, - euiColorStops__track: css` - &::after { - background: ${stripesBackground}; - background-size: ${euiTheme.size.xs} ${euiTheme.size.xs}; /* Percentage stops and background-size are both needed for Safari to render the gradient at fullWidth correctly */ - } - `, - euiColorStops__addTarget: css` - ${euiCustomControl(euiThemeContext, { type: 'round' })} - ${euiRangeThumbStyle(euiThemeContext)} - position: absolute; - inset-block-start: 0; - block-size: ${range.thumbHeight}; - inline-size: ${range.thumbHeight}; - background-color: ${euiTheme.colors.lightestShade}; - pointer-events: none; - opacity: 0; - border: ${euiTheme.border.width.thin} solid ${euiTheme.colors.darkShade}; - box-shadow: none; - z-index: ${range.thumbZIndex}; - - ${euiCanAnimate} { - transition: opacity ${euiTheme.animation.fast} ease-in; - } - `, - }; -}; - -export const euiColorStopsAddContainerStyles = ( - euiThemeContext: UseEuiTheme -) => { - const range = euiRangeVariables(euiThemeContext); - - return { - euiColorStopsAddContainer: css` - display: block; - position: absolute; - inset-inline-start: 0; - inset-inline-end: 0; - inset-block-start: 50%; - block-size: ${range.thumbHeight}; - margin-block-start: ${mathWithUnits(range.thumbHeight, (x) => x * -0.5)}; - z-index: ${range.thumbZIndex}; - `, - isEnabled: css` - &:hover { - cursor: pointer; - - .euiColorStops__addTarget { - opacity: 0.7; - } - } - `, - isDisabled: css``, - }; -}; diff --git a/src/components/color_picker/color_stops/color_stops.test.tsx b/src/components/color_picker/color_stops/color_stops.test.tsx deleted file mode 100644 index 889d51199f6..00000000000 --- a/src/components/color_picker/color_stops/color_stops.test.tsx +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { render } from '../../../test/rtl'; - -import { EuiColorStops } from './color_stops'; - -import { - VISUALIZATION_COLORS, - DEFAULT_VISUALIZATION_COLOR, - keys, -} from '../../../services'; -import { requiredProps, findTestSubject } from '../../../test'; -import { shouldRenderCustomStyles } from '../../../test/internal'; -import { EuiFieldNumber } from '../../form/field_number'; - -jest.mock('../../portal', () => ({ - EuiPortal: ({ children }: { children: any }) => children, -})); - -const onChange = jest.fn(); - -const colorStopsArray = [ - { stop: 0, color: '#FF0000' }, - { stop: 25, color: '#00FF00' }, - { stop: 35, color: '#0000FF' }, -]; - -// Note: A couple tests that would be nice, but can't be accomplished at the moment: -// - Tab to bypass thumbs (tabindex="-1" not respected) -// - Drag to reposition thumb (we can't get real page position info) - -shouldRenderCustomStyles( - -); - -test('renders EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders free-range EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders min-only EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders max-only EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders compressed EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders readOnly EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders fullWidth EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders disabled EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders fixed stop EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('renders stepped stop EuiColorStops', () => { - const { getByTestSubject } = render( - - ); - - expect( - getByTestSubject('euiRangeHighlightProgress').getAttribute('style') - ).toEqual('margin-inline-start: 0%; inline-size: 100%;'); -}); - -test('renders empty EuiColorStops', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); -}); - -test('popover color selector is shown when the thumb is clicked', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const colorSelector = findTestSubject(colorStops, 'euiColorStopPopover'); - expect(colorSelector.length).toBe(1); -}); - -test('passes value input props to number input', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const colorSelector = findTestSubject(colorStops, 'euiColorStopPopover'); - expect(colorSelector.find(EuiFieldNumber).prop('append')).toEqual('%'); -}); - -test('stop input updates stops', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const event = { target: { value: '10' } }; - const inputs = colorStops.find('input[type="number"]'); - expect(inputs.length).toBe(1); - inputs.simulate('change', event); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 10 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); -}); - -test('stop input updates stops with error prevention (reset to bounds)', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const event = { target: { value: '1000' } }; - const inputs = colorStops.find('input[type="number"]'); - inputs.simulate('change', event); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 100 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); -}); - -test('hex input updates stops', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const event = { target: { value: '#FFFFFF' } }; - const inputs = colorStops.find('input[type="text"]'); - expect(inputs.length).toBe(1); - inputs.simulate('change', event); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: '#FFFFFF', stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); -}); - -test('hex input updates stops with error', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const event = { target: { value: '#FFFFF' } }; - const inputs = colorStops.find('input[type="text"]'); - inputs.simulate('change', event); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: '#FFFFF', stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - true // isInvalid - ); -}); - -test('picker updates stops', () => { - const colorStops = mount( - - ); - - findTestSubject(colorStops, 'euiColorStopThumb') - .first() - .simulate('mousedown', { pageX: 0, pageY: 0 }) - .simulate('mouseup', { pageX: 0, pageY: 0 }); - const swatches = colorStops.find('button.euiColorPicker__swatchSelect'); - expect(swatches.length).toBe(VISUALIZATION_COLORS.length); - swatches.first().simulate('click'); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: VISUALIZATION_COLORS[0], stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); -}); - -test('thumb focus changes', () => { - const colorStops = mount( - - ); - - const wrapper = findTestSubject(colorStops, 'euiColorStops'); - const thumbs = findTestSubject(colorStops, 'euiColorStopThumb'); - wrapper.simulate('focus'); - wrapper.simulate('keydown', { - key: keys.ARROW_DOWN, - }); - expect(thumbs.first().getDOMNode()).toEqual(document.activeElement); - thumbs.first().simulate('keydown', { - key: keys.ARROW_DOWN, - }); - expect(thumbs.at(1).getDOMNode()).toEqual(document.activeElement); -}); - -test('thumb direction movement', () => { - const colorStops = mount( - - ); - - const wrapper = findTestSubject(colorStops, 'euiColorStops'); - const thumbs = findTestSubject(colorStops, 'euiColorStopThumb'); - wrapper.simulate('focus'); - wrapper.simulate('keydown', { - key: keys.ARROW_DOWN, - }); - expect(thumbs.first().getDOMNode()).toEqual(document.activeElement); - thumbs.first().simulate('keydown', { - key: keys.ARROW_RIGHT, - }); - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 1 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); - thumbs.first().simulate('keydown', { - key: keys.ARROW_LEFT, - }); - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - ], - false - ); -}); - -test('add new thumb via keyboard', () => { - const colorStops = mount( - - ); - - const wrapper = findTestSubject(colorStops, 'euiColorStops'); - wrapper.simulate('focus'); - wrapper.simulate('keydown', { - key: keys.ENTER, - }); - expect(onChange).toBeCalled(); - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - { color: DEFAULT_VISUALIZATION_COLOR, stop: 45 }, - ], - false - ); -}); - -test('add new thumb via click', () => { - const colorStops = mount( - - ); - - const wrapper = findTestSubject(colorStops, 'euiColorStopsAdd'); - wrapper.simulate('click', { pageX: 45, pageY: 0 }); - expect(onChange).toBeCalled(); - // This is a very odd expectation. - // But we can't get actual page positions in this environment (no getBoundingClientRect) - // So we'll expect the _correct_ color and _incorrect_ stop value (NaN), - // with the `isInvalid` arg _correctly_ true as a result. - expect(onChange).toBeCalledWith( - [ - { color: '#FF0000', stop: 0 }, - { color: '#00FF00', stop: 25 }, - { color: '#0000FF', stop: 35 }, - { color: DEFAULT_VISUALIZATION_COLOR, stop: NaN }, - ], - true // isInvalid - ); -}); diff --git a/src/components/color_picker/color_stops/color_stops.tsx b/src/components/color_picker/color_stops/color_stops.tsx deleted file mode 100644 index 75712428b08..00000000000 --- a/src/components/color_picker/color_stops/color_stops.tsx +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { - FunctionComponent, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; -import classNames from 'classnames'; - -import { CommonProps } from '../../common'; -import { - keys, - DEFAULT_VISUALIZATION_COLOR, - getSteppedGradient, - useEuiTheme, -} from '../../../services'; -import { EuiColorStopThumb, ColorStop } from './color_stop_thumb'; -import { - addStop, - addDefinedStop, - getPositionFromStop, - getStopFromMouseLocation, - isInvalid, - removeStop, -} from './utils'; - -import { EuiColorPickerProps } from '../color_picker'; -import { getChromaColor } from '../utils'; -import { EuiI18n } from '../../i18n'; -import { EuiScreenReaderOnly } from '../../accessibility'; -import { EuiRangeHighlight } from '../../form/range/range_highlight'; -import { EuiRangeTrack } from '../../form/range/range_track'; -import { EuiRangeWrapper } from '../../form/range/range_wrapper'; -import { EuiFieldNumberProps } from '../../form/field_number'; - -import { - euiColorStopsStyles, - euiColorStopsAddContainerStyles, -} from './color_stops.styles'; - -/** - * @deprecated - */ -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; - disabled?: boolean; - readOnly?: boolean; - invalid?: boolean; - compressed?: boolean; - className?: string; - max?: number; - min?: number; - label: string; - /** - * Specify the type of stops: - * `fixed`: individual color blocks. - * `gradient`: each color fades into the next. - * `stepped`: interpolation between colors with a fixed number of steps. - */ - stopType?: 'fixed' | 'gradient' | 'stepped'; - /** - * Only works when `stopType="stepped"` - */ - stepNumber?: number; - mode?: EuiColorPickerProps['mode']; - swatches?: EuiColorPickerProps['swatches']; - showAlpha?: EuiColorPickerProps['showAlpha']; - /** - * Props passed to the value input field in the color stop popover. - * Can be used to configure functionality like append or prepend. - */ - valueInputProps?: Partial< - Omit< - EuiFieldNumberProps, - | 'inputRef' - | 'compressed' - | 'readOnly' - | 'min' - | 'max' - | 'value' - | 'isInvalid' - | 'onChange' - > - >; -} - -// Because of how the thumbs are rendered in the popover, using ref results in an infinite loop. -// We'll instead use old fashioned namespaced DOM selectors to get references -const STOP_ATTR = 'euiColorStop_'; - -const DEFAULT_MIN = 0; -const DEFAULT_MAX = 100; - -function isTargetAThumb(target: HTMLElement | EventTarget) { - const element = target as HTMLElement; - const attr = element.getAttribute('data-index'); - return attr && attr.indexOf(STOP_ATTR) > -1; -} - -function sortStops(colorStops: ColorStop[]) { - return colorStops - .map((el, index) => { - return { - ...el, - id: index, - }; - }) - .sort((a, b) => a.stop - b.stop); -} - -function getValidStops(colorStops: ColorStop[]) { - return colorStops.map((el) => el.stop).filter((stop) => !isNaN(stop)); -} - -function getRangeMin(colorStops: ColorStop[], min?: number) { - const rangeMin = min || DEFAULT_MIN; - const stops = getValidStops(colorStops); - const first = Math.min(...stops); // https://johnresig.com/blog/fast-javascript-maxmin/ - - if (first < rangeMin) { - if (stops.length === 1) { - return first - DEFAULT_MIN; - } else if (stops.length >= 2) { - return first; - } - } - return DEFAULT_MIN; -} -function getRangeMax(colorStops: ColorStop[], max?: number) { - const rangeMax = max || DEFAULT_MAX; - const stops = getValidStops(colorStops); - const last = Math.max(...stops); // https://johnresig.com/blog/fast-javascript-maxmin/ - - if (last > rangeMax) { - if (stops.length === 1) { - return last + DEFAULT_MAX; - } else if (stops.length >= 2) { - return last; - } - } - return DEFAULT_MAX; -} - -/** - * @deprecated - EuiColorStops is scheduled for deprecation due to low internal usage and high - * maintenance requirements. If necessary, we recommend copying this component into your own application. - * - * The component will be permanently removed in October 2023. - */ -export const EuiColorStops: FunctionComponent = ({ - addColor = DEFAULT_VISUALIZATION_COLOR, - max, - min, - mode = 'default', - colorStops, - onChange, - disabled, - readOnly, - compressed, - fullWidth, - className, - label, - stopType = 'gradient', - stepNumber = 10, - swatches, - showAlpha = false, - valueInputProps, - ...rest -}) => { - const sortedStops = useMemo(() => sortStops(colorStops), [colorStops]); - const rangeMax: number = useMemo(() => { - const result = max != null ? max : getRangeMax(colorStops, max); - const width = max != null ? 0 : Math.round(result * 0.05); - return !isNaN(result) ? result + width : DEFAULT_MAX; - }, [colorStops, max]); - const rangeMin: number = useMemo(() => { - const result = min != null ? min : getRangeMin(colorStops, min); - const width = min != null ? 0 : Math.round(rangeMax * 0.05); - return !isNaN(result) ? result - width : DEFAULT_MIN; - }, [colorStops, min, rangeMax]); - const [hasFocus, setHasFocus] = useState(false); - const [focusedStopIndex, setFocusedStopIndex] = useState(null); - const [openedStopId, setOpenedStopId] = useState(null); - const [wrapperRef, setWrapperRef] = useState(null); - const [addTargetPosition, setAddTargetPosition] = useState(0); - const [isHoverDisabled, setIsHoverDisabled] = useState(false); - const [focusStopOnUpdate, setFocusStopOnUpdate] = useState( - null - ); - - const isNotInteractive = disabled || readOnly; - const isDragging = isHoverDisabled && !isNotInteractive; - const addContainerIsDisabled = isHoverDisabled || isNotInteractive; - - const classes = classNames('euiColorStops', className); - - const euiTheme = useEuiTheme(); - const styles = euiColorStopsStyles(euiTheme); - const cssPopoverStyles = [ - styles.euiColorStops, - !disabled ? styles.isEnabled : styles.isDisabled, - readOnly && styles.isReadOnly, - isDragging && styles.isDragging, - ]; - const cssTrackStyles = [styles.euiColorStops__track]; - const cssAddTargetStyles = [styles.euiColorStops__addTarget]; - - const addContainerStyles = euiColorStopsAddContainerStyles(euiTheme); - const cssAddContainerStyles = [ - addContainerStyles.euiColorStopsAddContainer, - !addContainerIsDisabled - ? addContainerStyles.isEnabled - : addContainerStyles.isDisabled, - ]; - - const getStopFromMouseLocationFn = (location: { x: number; y: number }) => { - // Guard against `null` ref in usage - return getStopFromMouseLocation( - location, - wrapperRef!, - min || rangeMin, - max || rangeMax - ); - }; - - const getPositionFromStopFn = (stop: ColorStop['stop']) => { - // Guard against `null` ref in usage - return getPositionFromStop( - stop, - wrapperRef!, - min || rangeMin, - max || rangeMax - ); - }; - - const handleOnChange = useCallback( - (colorStops: ColorStop[]) => { - onChange(colorStops, isInvalid(colorStops, showAlpha)); - }, - [onChange, showAlpha] - ); - - const onFocusStop = useCallback( - (index: number) => { - if (disabled || !wrapperRef) return; - const toFocus = wrapperRef.querySelector( - `[data-index=${STOP_ATTR}${index}]` - ); - if (toFocus) { - setHasFocus(false); - setFocusedStopIndex(index); - toFocus.focus(); - } - }, - [disabled, wrapperRef] - ); - - useEffect(() => { - if (focusStopOnUpdate !== null) { - const toFocusIndex = sortedStops - .map((el) => el.stop) - .indexOf(focusStopOnUpdate); - const toFocusId = toFocusIndex > -1 ? sortedStops[toFocusIndex].id : null; - onFocusStop(toFocusIndex); - setOpenedStopId(toFocusId); - setFocusStopOnUpdate(null); - } - }, [sortedStops, onFocusStop, setFocusStopOnUpdate, focusStopOnUpdate]); - - const onFocusWrapper = useCallback(() => { - setFocusedStopIndex(null); - if (wrapperRef) { - wrapperRef.focus(); - } - }, [wrapperRef]); - - const setWrapperHasFocus = (e: React.FocusEvent) => { - if (e.target === wrapperRef) { - setHasFocus(true); - } - }; - - const removeWrapperFocus = () => { - setHasFocus(false); - }; - - const onAdd = () => { - const stops = sortedStops.map(({ color, stop }) => { - return { - color, - stop, - }; - }); - const newColorStops = addStop(stops, addColor, max || rangeMax); - - setFocusStopOnUpdate(newColorStops[colorStops.length].stop); - handleOnChange(newColorStops); - }; - - const onRemove = useCallback( - (index: number) => { - const newColorStops = removeStop(colorStops, index); - - onFocusWrapper(); - handleOnChange(newColorStops); - }, - [colorStops, handleOnChange, onFocusWrapper] - ); - - const disableHover = () => { - if (disabled) return; - setIsHoverDisabled(true); - }; - - const enableHover = () => { - if (disabled) return; - setIsHoverDisabled(false); - }; - - const handleAddHover = (e: React.MouseEvent) => { - if (isNotInteractive || !wrapperRef) return; - const stop = getStopFromMouseLocationFn({ x: e.pageX, y: e.pageY }); - const position = getPositionFromStopFn(stop); - - setAddTargetPosition(position); - }; - - const handleAddClick = (e: React.MouseEvent) => { - if (isNotInteractive || isTargetAThumb(e.target) || !wrapperRef) return; - const newStop = getStopFromMouseLocationFn({ x: e.pageX, y: e.pageY }); - const newColorStops = addDefinedStop(colorStops, newStop, addColor); - setFocusStopOnUpdate(newStop); - handleOnChange(newColorStops); - }; - - const handleKeyDown = (event: React.KeyboardEvent) => { - if (disabled) return; - switch (event.key) { - case keys.ESCAPE: - onFocusWrapper(); - break; - - case keys.ENTER: - if (readOnly || !hasFocus) return; - onAdd(); - break; - - case keys.BACKSPACE: - if (readOnly || hasFocus || focusedStopIndex == null) return; - if (isTargetAThumb(event.target)) { - if ( - (min == null && focusedStopIndex === 0) || - (max == null && focusedStopIndex === sortedStops.length - 1) - ) { - return; - } - const index = sortedStops[focusedStopIndex].id; - onRemove(index); - } - break; - - case keys.ARROW_DOWN: - if (event.target === wrapperRef || isTargetAThumb(event.target)) { - event.preventDefault(); - if (focusedStopIndex == null) { - onFocusStop(0); - } else { - const next = - focusedStopIndex === sortedStops.length - 1 - ? focusedStopIndex - : focusedStopIndex + 1; - onFocusStop(next); - } - } - break; - - case keys.ARROW_UP: - if (event.target === wrapperRef || isTargetAThumb(event.target)) { - event.preventDefault(); - if (focusedStopIndex == null) { - onFocusStop(0); - } else { - const next = - focusedStopIndex === 0 ? focusedStopIndex : focusedStopIndex - 1; - onFocusStop(next); - } - } - break; - } - }; - - const thumbs = useMemo(() => { - const handleStopChange = (stop: ColorStop, id: number) => { - const newColorStops = [...colorStops]; - newColorStops.splice(id, 1, stop); - handleOnChange(newColorStops); - }; - return sortedStops.map((colorStop, index) => ( - 1 ? () => onRemove(colorStop.id) : undefined - } - onChange={(stop) => handleStopChange(stop, colorStop.id)} - onFocus={() => setFocusedStopIndex(index)} - parentRef={wrapperRef} - colorPickerMode={mode} - colorPickerShowAlpha={showAlpha} - colorPickerSwatches={swatches} - disabled={disabled} - readOnly={readOnly} - aria-valuetext={`Stop: ${colorStop.stop}, Color: ${colorStop.color} (${ - index + 1 - } of ${colorStops.length})`} - isPopoverOpen={!isDragging && colorStop.id === openedStopId} - openPopover={() => { - setOpenedStopId(colorStop.id); - }} - closePopover={() => { - setOpenedStopId(null); - }} - valueInputProps={valueInputProps} - /> - )); - }, [ - colorStops, - disabled, - handleOnChange, - isDragging, - max, - min, - mode, - onRemove, - openedStopId, - rangeMax, - rangeMin, - readOnly, - showAlpha, - sortedStops, - swatches, - wrapperRef, - valueInputProps, - ]); - - const positions = wrapperRef - ? sortedStops.map(({ stop }) => getPositionFromStopFn(stop)) - : []; - const gradientStop = (colorStop: ColorStop, index: number) => { - const color = getChromaColor(colorStop.color, showAlpha); - const rgba = color ? color.css() : 'transparent'; - if (index === 0) { - return `transparent, transparent ${positions[index]}%, ${rgba} ${positions[index]}%`; - } - return `${rgba} ${positions[index]}%`; - }; - const fixedStop = (colorStop: ColorStop, index: number) => { - if (index === sortedStops.length - 1) { - return gradientStop(colorStop, index); - } else { - return `${gradientStop(colorStop, index)}, ${gradientStop( - colorStop, - index + 1 - )}`; - } - }; - - let gradient: string = ''; - - if (stopType === 'stepped' && positions.length > 0) { - const trailingPercentage = positions[0]; - const endingPercentage = positions[positions.length - 1]; - const steppedColors = getSteppedGradient(colorStops, stepNumber); - let steppedGradient = ''; - const percentage = - (endingPercentage - trailingPercentage) / steppedColors.length; - let percentageSteps = - (endingPercentage - trailingPercentage) / steppedColors.length + - trailingPercentage; - steppedColors.forEach((color) => { - steppedGradient = steppedGradient.concat( - `${color} ${percentageSteps - percentage}% ${percentageSteps}%, ` - ); - percentageSteps = percentageSteps + percentage; - }); - steppedGradient = steppedGradient.substring(0, steppedGradient.length - 2); - gradient = `linear-gradient(to right, transparent ${trailingPercentage}%, ${steppedGradient})`; - } else { - const linearGradient = sortedStops.map( - stopType === 'gradient' ? gradientStop : fixedStop - ); - gradient = `linear-gradient(to right,${linearGradient})`; - } - - return ( - - -

- -

-
- - {(trackWidth) => ( - <> - -
-
-
- {thumbs} - - )} - - - ); -}; diff --git a/src/components/color_picker/color_stops/index.ts b/src/components/color_picker/color_stops/index.ts deleted file mode 100644 index 2ac47a5781c..00000000000 --- a/src/components/color_picker/color_stops/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export { EuiColorStops } from './color_stops'; diff --git a/src/components/color_picker/color_stops/utils.test.ts b/src/components/color_picker/color_stops/utils.test.ts deleted file mode 100644 index 814a0525fc4..00000000000 --- a/src/components/color_picker/color_stops/utils.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { addStop, addDefinedStop, removeStop, isInvalid } from './utils'; - -const colorStops = [ - { stop: 0, color: '#FF0000' }, - { stop: 25, color: '#00FF00' }, - { stop: 35, color: '#0000FF' }, -]; - -describe('isInvalid', () => { - test('Should not mark valid colorStops as invalid', () => { - expect(isInvalid(colorStops)).toBe(false); - }); - - test('Should mark colorStops missing color as invalid', () => { - const colorStops = [{ stop: 0, color: '' }]; - expect(isInvalid(colorStops)).toBe(true); - }); - - test('Should mark colorStops with invalid color as invalid', () => { - const colorStops = [{ stop: 0, color: 'not color' }]; - expect(isInvalid(colorStops)).toBe(true); - }); - - test('Should mark colorStops missing stop as invalid', () => { - const colorStops = [{ stop: null, color: '#FF0000' }]; - // @ts-ignore Intentionally wrong - expect(isInvalid(colorStops)).toBe(true); - }); - - test('Should mark colorStops with invalid stop as invalid', () => { - const colorStops = [{ stop: 'I am not a number', color: '#FF0000' }]; - // @ts-ignore Intentionally wrong - expect(isInvalid(colorStops)).toBe(true); - }); -}); - -describe('addStop', () => { - test('Should add stop when there is only a single stop', () => { - const colorStops = [{ stop: 0, color: '#FF0000' }]; - expect(addStop(colorStops, '#FF0000', 100)).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 1, color: '#FF0000' }, - ]); - }); - - test('Should add stop to end of list', () => { - expect(addStop(colorStops, '#FF0000', 100)).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 25, color: '#00FF00' }, - { stop: 35, color: '#0000FF' }, - { stop: 45, color: '#FF0000' }, - ]); - }); - - test('Should add stop below the max if max is taken', () => { - expect( - addStop( - [ - { stop: 0, color: '#FF0000' }, - { stop: 100, color: '#FF0000' }, - ], - '#FF0000', - 100 - ) - ).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 100, color: '#FF0000' }, - { stop: 99, color: '#FF0000' }, - ]); - }); -}); - -describe('addDefinedStop', () => { - const colorStops = [{ stop: 0, color: '#FF0000' }]; - test('Should add stop', () => { - expect(addDefinedStop(colorStops, 1)).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 1, color: '#6092C0' }, - ]); - }); - - test('Should add stop with a specified color', () => { - expect(addDefinedStop(colorStops, 1, '#FFFFFF')).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 1, color: '#FFFFFF' }, - ]); - }); -}); - -describe('removeStop', () => { - test('Should not remove only stop', () => { - const colorStops = [{ stop: 0, color: '#FF0000' }]; - expect(removeStop(colorStops, 0)).toEqual(colorStops); - }); - - test('Should remove stop at index', () => { - const colorStops = [ - { stop: 0, color: '#FF0000' }, - { stop: 25, color: '#00FF00' }, - { stop: 35, color: '#0000FF' }, - ]; - expect(removeStop(colorStops, 1)).toEqual([ - { stop: 0, color: '#FF0000' }, - { stop: 35, color: '#0000FF' }, - ]); - }); -}); diff --git a/src/components/color_picker/color_stops/utils.ts b/src/components/color_picker/color_stops/utils.ts deleted file mode 100644 index f09e07659bf..00000000000 --- a/src/components/color_picker/color_stops/utils.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { getEventPosition, getChromaColor } from '../utils'; -import { DEFAULT_VISUALIZATION_COLOR } from '../../../services'; -import { ColorStop } from './color_stop_thumb'; -import { EUI_THUMB_SIZE } from '../../form/range/utils'; - -export const removeStop = (colorStops: ColorStop[], index: number) => { - if (colorStops.length === 1) { - return colorStops; - } - - return [...colorStops.slice(0, index), ...colorStops.slice(index + 1)]; -}; - -export const addDefinedStop = ( - colorStops: ColorStop[], - stop: ColorStop['stop'], - color: ColorStop['color'] = DEFAULT_VISUALIZATION_COLOR -) => { - const newStop = { - stop, - color, - }; - colorStops = [...colorStops, newStop]; - colorStops.sort((a, b) => { - if (a.stop < b.stop) { - return -1; - } - if (a.stop > b.stop) { - return 1; - } - return 0; - }); - return colorStops; -}; - -export const addStop = ( - colorStops: ColorStop[], - color: ColorStop['color'] = DEFAULT_VISUALIZATION_COLOR, - max: number -) => { - const index = colorStops.length ? colorStops.length - 1 : 0; - const stops = colorStops.map((el) => el.stop); - const currentStop = stops[index] != null ? stops[index] : max; - let delta = 1; - if (index !== 0) { - const prevStop = stops[index - 1]; - delta = currentStop - prevStop; - } - - let stop = currentStop + delta; - - if (stop > max) { - stop = max; - } - - // We've reached the max, so start working backwards - while (stops.indexOf(stop) > -1) { - stop--; - } - - const newStop = { - stop, - color, - }; - return [ - ...colorStops.slice(0, index + 1), - newStop, - ...colorStops.slice(index + 1), - ]; -}; - -export const isColorInvalid = (color: string, showAlpha: boolean = false) => { - return getChromaColor(color, showAlpha) == null || color === ''; -}; - -export const isStopInvalid = (stop: ColorStop['stop']) => { - return stop == null || isNaN(stop); -}; - -export const isInvalid = ( - colorStops: ColorStop[], - showAlpha: boolean = false -) => { - return colorStops.some((colorStop) => { - return ( - isColorInvalid(colorStop.color, showAlpha) || - isStopInvalid(colorStop.stop) - ); - }); -}; - -export const calculateScale = (trackWidth: number) => { - const thumbToTrackRatio = EUI_THUMB_SIZE / trackWidth; - return (1 - thumbToTrackRatio) * 100; -}; - -export const getStopFromMouseLocation = ( - location: { x: number; y: number }, - ref: HTMLDivElement, - min: number, - max: number -) => { - const box = getEventPosition(location, ref); - return Math.round((box.left / box.width) * (max - min) + min); -}; - -export const getPositionFromStop = ( - stop: ColorStop['stop'], - ref: HTMLDivElement, - min: number, - max: number -) => { - // For wide implementations, integer percentages can be visually off. - // Use 1 decimal place for more accuracy - return parseFloat( - ( - ((stop - min) / (max - min)) * - calculateScale(ref && ref.clientWidth > 0 ? ref.clientWidth : 100) - ).toFixed(1) - ); -}; diff --git a/src/components/color_picker/index.ts b/src/components/color_picker/index.ts index 633320d6938..eba48810e49 100644 --- a/src/components/color_picker/index.ts +++ b/src/components/color_picker/index.ts @@ -14,11 +14,6 @@ export type { EuiHueProps } from './hue'; export { EuiHue } from './hue'; export type { EuiSaturationProps } from './saturation'; export { EuiSaturation } from './saturation'; -export { EuiColorStops } from './color_stops'; -// TODO: Exporting `EuiColorStopsProps` from `'./color_stops'` -// results in a duplicate d.ts entry that causes build warnings -// and potential downstream TS project failures. -export type { EuiColorStopsProps } from './color_stops/color_stops'; export type { EuiColorPalettePickerProps, EuiColorPalettePickerPaletteProps, diff --git a/upcoming_changelogs/7262.md b/upcoming_changelogs/7262.md new file mode 100644 index 00000000000..96dd9760b85 --- /dev/null +++ b/upcoming_changelogs/7262.md @@ -0,0 +1,3 @@ +**Breaking changes** + +- Removed `EuiColorStops` due to low usage