diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2486acf7cad..73e57aa9831 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
- Added `popoverPlacement` prop in `EuiDatePicker` ([#3359](https://github.com/elastic/eui/pull/3359))
- Extended `EuiDatePicker`'s `startDate` and `endDate` types to accept `null` values for better interoperability ([#3343](https://github.com/elastic/eui/pull/3343))
- Added `EuiCommentList` component ([#3344](https://github.com/elastic/eui/pull/3344))
+- Added secondary color value input element to `EuiColorPicker` ([#3336](https://github.com/elastic/eui/pull/3336))
**Bug Fixes**
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 1f90a21358c..5aaf9300bd8 100644
--- a/src-docs/src/views/color_picker/color_picker_example.js
+++ b/src-docs/src/views/color_picker/color_picker_example.js
@@ -122,6 +122,7 @@ const customButtonHtml = renderToHtml(CustomButton);
const customButtonSnippet = `
- Available only in EuiColorPicker. You can optionally
- use a custom button as the trigger for selection using the{' '}
- button prop. Please remember to add accessibility
- to this component, using proper button markup and aria labeling.
-
+ <>
+
+ Available only in EuiColorPicker. You can
+ optionally use a custom button as the trigger for selection using
+ the button prop. Please remember to add
+ accessibility to this component, using proper button markup and aria
+ labeling.
+
+
+ Additionally, use the secondaryInputDisplay prop
+ to show a secondary or alternative color value input. Options
+ include top and bottom{' '}
+ placement.
+
+ >
),
snippet: [customButtonSnippet, customBadgeSnippet],
demo: ,
diff --git a/src-docs/src/views/color_picker/custom_button.js b/src-docs/src/views/color_picker/custom_button.js
index e8c227cd011..a18b6235f31 100644
--- a/src-docs/src/views/color_picker/custom_button.js
+++ b/src-docs/src/views/color_picker/custom_button.js
@@ -23,6 +23,7 @@ export const CustomButton = () => {
{
onChange={handleColorChange}
color={color}
isInvalid={!!errors}
+ secondaryInputDisplay="bottom"
button={
{
});
});
-test('default mode does redners child components', () => {
+test('default mode does renders child components', () => {
const colorPicker = mount(
);
@@ -334,3 +334,37 @@ test('picker mode does not render swatches', () => {
const swatches = colorPicker.find('button.euiColorPicker__swatchSelect');
expect(swatches.length).toBe(0);
});
+
+test('secondaryInputDisplay `top` has a popover panel input', () => {
+ const colorPicker = mount(
+
+ );
+
+ findTestSubject(colorPicker, 'colorPickerAnchor').simulate('click');
+ const inputTop = findTestSubject(colorPicker, 'topColorPickerInput');
+ const inputBottom = findTestSubject(colorPicker, 'bottomColorPickerInput');
+ expect(inputTop.length).toBe(1);
+ expect(inputBottom.length).toBe(0);
+});
+
+test('secondaryInputDisplay `bottom` has a popover panel input', () => {
+ const colorPicker = mount(
+
+ );
+
+ findTestSubject(colorPicker, 'colorPickerAnchor').simulate('click');
+ const inputTop = findTestSubject(colorPicker, 'topColorPickerInput');
+ const inputBottom = findTestSubject(colorPicker, 'bottomColorPickerInput');
+ expect(inputTop.length).toBe(0);
+ expect(inputBottom.length).toBe(1);
+});
diff --git a/src/components/color_picker/color_picker.tsx b/src/components/color_picker/color_picker.tsx
index 32982a47cdc..3ec4e6190d9 100644
--- a/src/components/color_picker/color_picker.tsx
+++ b/src/components/color_picker/color_picker.tsx
@@ -40,6 +40,7 @@ import {
EuiFieldText,
EuiFormControlLayout,
EuiFormControlLayoutProps,
+ EuiFormRow,
EuiRange,
} from '../form';
import { EuiI18n } from '../i18n';
@@ -59,7 +60,7 @@ import {
} from './utils';
type EuiColorPickerDisplay = 'default' | 'inline';
-type EuiColorPickerMode = 'default' | 'swatch' | 'picker';
+type EuiColorPickerMode = 'default' | 'swatch' | 'picker' | 'secondaryInput';
export interface EuiColorPickerOutput {
rgba: ColorSpaces['rgba'];
@@ -106,7 +107,7 @@ export interface EuiColorPickerProps
*/
isInvalid?: boolean;
/**
- * Choose between swatches with gradient picker (default), swatches only, or gradient picker only.
+ * Choose between swatches with gradient picker (default), swatches only, gradient picker only, or secondary input only.
*/
mode?: EuiColorPickerMode;
/**
@@ -140,6 +141,10 @@ export interface EuiColorPickerProps
* Default is to display the last format entered by the user
*/
format?: 'hex' | 'rgba';
+ /**
+ * Placement option for a secondary color value input.
+ */
+ secondaryInputDisplay?: 'top' | 'bottom' | 'none';
}
function isKeyboardEvent(
@@ -201,6 +206,7 @@ export const EuiColorPicker: FunctionComponent = ({
append,
showAlpha = false,
format,
+ secondaryInputDisplay = 'none',
}) => {
const preferredFormat = useMemo(() => {
if (format) return format;
@@ -248,7 +254,8 @@ export const EuiColorPicker: FunctionComponent = ({
const classes = classNames('euiColorPicker', className);
const popoverClass = 'euiColorPicker__popoverAnchor';
const panelClasses = classNames('euiColorPicker__popoverPanel', {
- 'euiColorPicker__popoverPanel--pickerOnly': mode === 'picker',
+ 'euiColorPicker__popoverPanel--pickerOnly':
+ mode === 'picker' && secondaryInputDisplay !== 'bottom',
'euiColorPicker__popoverPanel--customButton': button,
});
const swatchClass = 'euiColorPicker__swatchSelect';
@@ -414,9 +421,49 @@ export const EuiColorPicker: FunctionComponent = ({
}
};
+ const inlineInput = secondaryInputDisplay !== 'none' && (
+
+ {([colorLabel, colorErrorMessage, transparent]: string[]) => (
+
+
+
+ )}
+
+ );
+
+ const showSecondaryInputOnly = mode === 'secondaryInput';
+ const showPicker = mode !== 'swatch' && !showSecondaryInputOnly;
+ const showSwatches = mode !== 'picker' && !showSecondaryInputOnly;
+
const composite = (
-
- {mode !== 'swatch' && (
+ <>
+ {secondaryInputDisplay === 'top' && (
+ <>
+ {inlineInput}
+
+ >
+ )}
+ {showPicker && (
= ({
/>
)}
- {mode !== 'picker' && (
+ {showSwatches && (
{swatches.map((swatch, index) => (
@@ -456,8 +503,14 @@ export const EuiColorPicker: FunctionComponent = ({
))}
)}
+ {secondaryInputDisplay === 'bottom' && (
+ <>
+ {mode !== 'picker' && }
+ {inlineInput}
+ >
+ )}
{showAlpha && (
-
+ <>
= ({
/>
)}
-
+ >
)}
-
+ >
);
let buttonOrInput;
@@ -514,18 +567,23 @@ export const EuiColorPicker: FunctionComponent = ({
color: colorStyle,
}}>
- {([openLabel, closeLabel]: string[]) => (
+ {([openLabel, closeLabel, transparent]: string[]) => (
= ({
onChange({ stop, color: value });
};
- const handleColorInputChange = (e: React.ChangeEvent) =>
- handleColorChange(e.target.value);
-
const handleStopChange = (value: ColorStop['stop']) => {
const willBeInvalid = value > localMax || value < localMin;
@@ -353,65 +350,41 @@ export const EuiColorStopThumb: FunctionComponent = ({
)}
-
-
-
- {(removeLabel: string) => (
-
- )}
-
-
-
+ {!readOnly && (
+
+
+
+ {(removeLabel: string) => (
+
+ )}
+
+
+
+ )}
- {!readOnly && (
-
-
-
-
- )}
- {colorPickerMode !== 'swatch' && (
-
-
-
- {([hexLabel, hexErrorMessage]: React.ReactChild[]) => (
-
-
-
- )}
-
-
- )}
+ {!readOnly && }
+
);