diff --git a/packages/eui/src/components/form/form_control_layout/_form_control_layout_delimited.scss b/packages/eui/src/components/form/form_control_layout/_form_control_layout_delimited.scss
deleted file mode 100644
index e48ffb67185..00000000000
--- a/packages/eui/src/components/form/form_control_layout/_form_control_layout_delimited.scss
+++ /dev/null
@@ -1,67 +0,0 @@
-.euiFormControlLayoutDelimited {
- // Match just the regular drop shadow of inputs
- @include euiFormControlDefaultShadow;
- display: flex;
- align-items: stretch;
- padding: 1px; /* 1 */
-
- > .euiFormControlLayout__childrenWrapper {
- display: flex;
- align-items: center;
- width: 100%;
- background-color: $euiFormBackgroundColor;
- }
-
- // Target when the euiFormControlLayout is compressed without specifying the full class name in case it ever changes
- &[class*='-compressed'] {
- @include euiFormControlDefaultShadow($borderOnly: true);
- border-radius: $euiBorderRadius / 2;
- }
-
- // Target when the euiFormControlLayout is fullWidth without specifying the full class name in case it ever changes
- &[class*='-fullWidth'] .euiFormControlLayout__childrenWrapper,
- &[class*='-fullWidth'] .euiFormControlLayout__childrenWrapper > *:not(.euiFormControlLayoutDelimited__delimiter):not(.euiFormControlLayoutIcons) {
- width: 100%;
- max-width: none;
- }
-
- // Target when the euiFormControlLayout is disabled without specifying the full class name in case it ever changes
- &[class*='-isDisabled'] {
- @include euiFormControlDisabledStyle;
-
- .euiFormControlLayout__childrenWrapper {
- background-color: $euiFormBackgroundDisabledColor;
- }
- }
-
- // Target when the euiFormControlLayout is readOnly without specifying the full class name in case it ever changes
- &[class*='-readOnly'] {
- @include euiFormControlReadOnlyStyle;
-
- .euiFormControlLayout__childrenWrapper {
- background-color: $euiFormBackgroundReadOnlyColor;
- }
- }
-
- &--isInvalid .euiFormControlLayout__childrenWrapper {
- @include euiFormControlInvalidStyle;
- }
-}
-
-.euiFormControlLayoutDelimited__input {
- // stylelint-disable declaration-no-important
- box-shadow: none !important;
- border-radius: 0 !important;
- // stylelint-enable declaration-no-important
- text-align: center;
- height: 100%;
- min-width: 0; // Fixes FF
-}
-
-.euiFormControlLayoutDelimited__delimiter {
- align-self: stretch;
- flex-grow: 0;
- display: flex;
- align-items: center;
- line-height: 1; // Override EuiText line-height
-}
diff --git a/packages/eui/src/components/form/form_control_layout/_index.scss b/packages/eui/src/components/form/form_control_layout/_index.scss
deleted file mode 100644
index 63aeec7c19a..00000000000
--- a/packages/eui/src/components/form/form_control_layout/_index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import 'form_control_layout_delimited';
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts b/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts
index dbe9ae52c5c..024158cfa75 100644
--- a/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts
@@ -15,7 +15,7 @@ import {
mathWithUnits,
} from '../../../global_styling';
-import { euiFormControlDefaultShadow, euiFormVariables } from '../form.styles';
+import { euiFormVariables } from '../form.styles';
export const euiFormControlLayoutStyles = (euiThemeContext: UseEuiTheme) => {
const { euiTheme } = euiThemeContext;
@@ -45,14 +45,9 @@ export const euiFormControlLayoutStyles = (euiThemeContext: UseEuiTheme) => {
display: flex;
align-items: stretch;
- /* Account for inner box-shadow style border */
- padding: ${euiTheme.border.width.thin};
- ${euiFormControlDefaultShadow(euiThemeContext, {
- withBackground: false,
- })}
+ border: ${euiTheme.border.width.thin} solid ${form.borderColor};
background-color: ${form.backgroundColor};
- /* Keep backgrounds inside border radius */
- overflow: hidden;
+ overflow: hidden; /* Keep backgrounds inside border radius */
/* Force the stretch of any children so they expand the full height of the control */
> * {
@@ -144,14 +139,8 @@ export const euiFormControlLayoutSideNodeStyles = (
${logicalCSS('padding-right', euiTheme.size.s)}
}
`,
- append: css`
- ${logicalCSS('border-top-right-radius', 'inherit')}
- ${logicalCSS('border-bottom-right-radius', 'inherit')}
- `,
- prepend: css`
- ${logicalCSS('border-top-left-radius', 'inherit')}
- ${logicalCSS('border-bottom-left-radius', 'inherit')}
- `,
+ append: css``,
+ prepend: css``,
uncompressed: `
${text} {
${logicalCSS('padding-horizontal', euiTheme.size.xs)}
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout.test.tsx b/packages/eui/src/components/form/form_control_layout/form_control_layout.test.tsx
index ab0cf5bc8ac..2328d30bcc6 100644
--- a/packages/eui/src/components/form/form_control_layout/form_control_layout.test.tsx
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout.test.tsx
@@ -22,7 +22,9 @@ jest.mock('../../', () => ({
}));
describe('EuiFormControlLayout', () => {
- shouldRenderCustomStyles(
, {
+ childProps: ['wrapperProps'],
+ });
test('is rendered', () => {
const { container } = render(
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout.tsx b/packages/eui/src/components/form/form_control_layout/form_control_layout.tsx
index ca433b3e271..1c7438f648e 100644
--- a/packages/eui/src/components/form/form_control_layout/form_control_layout.tsx
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout.tsx
@@ -74,10 +74,17 @@ export type EuiFormControlLayoutProps = CommonProps &
* Connects the prepend and append labels to the input
*/
inputId?: string;
+ /**
+ * Allows passing optional additional props to `.euiFormControlLayout__childrenWrapper`
+ */
+ wrapperProps?: CommonProps & HTMLAttributes
;
};
export const EuiFormControlLayout: FunctionComponent<
- EuiFormControlLayoutProps
+ EuiFormControlLayoutProps & {
+ // Internal prop used by EuiFormControlLayoutDelimited
+ isDelimited?: boolean;
+ }
> = (props) => {
const { defaultFullWidth } = useFormContext();
const {
@@ -95,16 +102,18 @@ export const EuiFormControlLayout: FunctionComponent<
compressed,
prepend,
append,
+ isDelimited,
+ wrapperProps,
fullWidth = defaultFullWidth,
...rest
} = props;
- const isGroup = !!(prepend || append);
+ const isGroup = !!(prepend || append || isDelimited);
const classes = classNames(
'euiFormControlLayout',
{
- 'euiFormControlLayout--group': isGroup,
+ 'euiFormControlLayout--group': isGroup && !isDelimited,
'euiFormControlLayout-isDisabled': isDisabled,
'euiFormControlLayout-readOnly': readOnly,
},
@@ -130,6 +139,7 @@ export const EuiFormControlLayout: FunctionComponent<
isGroup && styles.children.inGroup,
isGroup && !append && styles.children.prependOnly,
isGroup && !prepend && styles.children.appendOnly,
+ wrapperProps?.css,
];
const hasDropdownIcon = !readOnly && !isDisabled && isDropdown;
@@ -159,9 +169,13 @@ export const EuiFormControlLayout: FunctionComponent<
compressed={compressed}
/>
{hasLeftIcon && (
),
},
+ render: ({ startControl, endControl, ...args }) => {
+ const { isInvalid, isDisabled, readOnly } = args;
+ const clonedControlProps = { isInvalid, disabled: isDisabled, readOnly };
+ return (
+
+ );
+ },
+};
+
+export const KitchenSink: Story = {
+ tags: ['vrt-only'],
+ render: function Render() {
+ const isDesktop = useIsWithinMinBreakpoint('xl');
+ return (
+
+ }
+ endControl={}
+ />
+ }
+ endControl={}
+ />
+ }
+ endControl={}
+ />
+ }
+ endControl={}
+ />
+ {} }}
+ isLoading
+ startControl={}
+ endControl={}
+ />
+ }
+ delimiter="+"
+ endControl={}
+ />
+ }
+ delimiter={}
+ endControl={}
+ />
+ }
+ endControl={}
+ />
+ }
+ endControl={}
+ />
+
+ }
+ endControl={
+
+ }
+ />
+
+ );
+ },
};
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.styles.ts b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.styles.ts
new file mode 100644
index 00000000000..f6cff7c3cb1
--- /dev/null
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.styles.ts
@@ -0,0 +1,66 @@
+/*
+ * 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 { logicalCSS } from '../../../global_styling';
+import {
+ euiFormControlDisabledStyles,
+ euiFormControlReadOnlyStyles,
+ euiFormControlDefaultShadow,
+ euiFormControlInvalidStyles,
+} from '../form.styles';
+
+export const euiFormControlLayoutDelimitedStyles = (
+ euiThemeContext: UseEuiTheme
+) => {
+ return {
+ // Appended onto existing `euiFormControlLayout` styles
+ delimited: css(
+ // Transition smoothly between disabled/readOnly background color changes
+ euiFormControlDefaultShadow(euiThemeContext, {
+ withBorder: false,
+ withBackground: false,
+ withBackgroundAnimation: true,
+ })
+ ),
+ disabled: css(euiFormControlDisabledStyles(euiThemeContext)),
+ readOnly: css(euiFormControlReadOnlyStyles(euiThemeContext)),
+
+ // Appended onto existing `euiFormControlLayout__childrenWrapper` styles
+ childrenWrapper: {
+ delimited: css`
+ display: flex;
+ `,
+ invalid: css(
+ euiFormControlDefaultShadow(euiThemeContext, {
+ withBorder: false,
+ withBackgroundColor: false,
+ withBackgroundAnimation: false,
+ }),
+ euiFormControlInvalidStyles(euiThemeContext)
+ ),
+ },
+ };
+};
+
+export const euiFormControlLayoutDelimited__delimiter = css`
+ align-self: stretch;
+ flex-grow: 0;
+ display: flex;
+ align-items: center;
+ line-height: 1; /* Override EuiText line-height */
+`;
+
+export const euiFormControlLayoutDelimited__input = css`
+ box-shadow: none;
+ border-radius: 0;
+ text-align: center;
+ ${logicalCSS('height', '100%')}
+`;
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.test.tsx b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.test.tsx
index 9d67f323582..0654758ed8c 100644
--- a/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.test.tsx
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.test.tsx
@@ -8,12 +8,23 @@
import React from 'react';
import { render } from '../../../test/rtl';
+import { shouldRenderCustomStyles } from '../../../test/internal';
import { requiredProps } from '../../../test/required_props';
-import { EuiFormControlLayoutDelimited } from './form_control_layout_delimited';
import { EuiIcon } from '../../icon';
+import { EuiForm } from '../form';
+
+import { EuiFormControlLayoutDelimited } from './form_control_layout_delimited';
describe('EuiFormControlLayoutDelimited', () => {
+ shouldRenderCustomStyles(
+ start}
+ endControl={end}
+ />,
+ { childProps: ['wrapperProps'] }
+ );
+
test('is rendered', () => {
const { container } = render(
{
});
});
});
+
+ describe('inherits', () => {
+ test('fullWidth from ', () => {
+ const { baseElement } = render(
+
+ start}
+ endControl={end}
+ />
+
+ );
+
+ const layout = baseElement.querySelector(
+ '.euiFormControlLayoutDelimited'
+ );
+ expect(layout!.className).toContain('fullWidth');
+ });
+ });
});
diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.tsx b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.tsx
index f6c5919976c..d4d2ba2180e 100644
--- a/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.tsx
+++ b/packages/eui/src/components/form/form_control_layout/form_control_layout_delimited.tsx
@@ -6,22 +6,24 @@
* Side Public License, v 1.
*/
-import React, {
- FunctionComponent,
- ReactElement,
- cloneElement,
- ReactNode,
-} from 'react';
+import React, { FunctionComponent, ReactElement, ReactNode } from 'react';
import classNames from 'classnames';
+import { useEuiMemoizedStyles, cloneElementWithCss } from '../../../services';
import { useEuiI18n } from '../../i18n';
import { EuiIcon } from '../../icon';
import { EuiText } from '../../text';
+import { FormContext, useFormContext } from '../eui_form_context';
import {
EuiFormControlLayout,
EuiFormControlLayoutProps,
} from './form_control_layout';
+import {
+ euiFormControlLayoutDelimitedStyles,
+ euiFormControlLayoutDelimited__delimiter,
+ euiFormControlLayoutDelimited__input,
+} from './form_control_layout_delimited.styles';
export type EuiFormControlLayoutDelimitedProps =
Partial & {
@@ -43,7 +45,17 @@ export type EuiFormControlLayoutDelimitedProps =
export const EuiFormControlLayoutDelimited: FunctionComponent<
EuiFormControlLayoutDelimitedProps
-> = ({ startControl, endControl, delimiter, className, ...rest }) => {
+> = ({
+ startControl,
+ endControl,
+ delimiter,
+ className,
+ fullWidth: _fullWidth,
+ ...rest
+}) => {
+ const { defaultFullWidth } = useFormContext();
+ const fullWidth = _fullWidth ?? defaultFullWidth;
+
const { isInvalid, isDisabled, readOnly } = rest;
const showInvalidState = isInvalid && !isDisabled && !readOnly;
@@ -51,25 +63,52 @@ export const EuiFormControlLayoutDelimited: FunctionComponent<
'euiFormControlLayoutDelimited--isInvalid': showInvalidState,
});
+ const styles = useEuiMemoizedStyles(euiFormControlLayoutDelimitedStyles);
+ const cssStyles = [
+ styles.delimited,
+ rest.isDisabled && styles.disabled,
+ rest.readOnly && styles.readOnly,
+ ];
+ const wrapperStyles = [
+ styles.childrenWrapper.delimited,
+ showInvalidState && styles.childrenWrapper.invalid,
+ rest.wrapperProps?.css,
+ ];
+
return (
-
- {addClassesToControl(startControl)}
-
- {addClassesToControl(endControl)}
+
+
+ {addClassesToControl(startControl)}
+
+ {addClassesToControl(endControl)}
+
);
};
const addClassesToControl = (control: ReactElement) => {
- return cloneElement(control, {
- className: classNames(
- control.props.className,
- 'euiFormControlLayoutDelimited__input'
- ),
- });
+ return cloneElementWithCss(
+ control,
+ {
+ css: euiFormControlLayoutDelimited__input,
+ className: classNames(
+ control.props.className,
+ 'euiFormControlLayoutDelimited__input'
+ ),
+ },
+ 'before'
+ );
};
const EuiFormControlDelimiter = ({
@@ -86,6 +125,7 @@ const EuiFormControlDelimiter = ({
return (
({
inline-size: auto;
min-inline-size: ${euiTheme.base * 4}px;
- .euiRange__popover & {
- margin: 0;
+ .euiRange__popover &,
+ .euiDualRange__popover & {
inline-size: 100%;
}
`,
diff --git a/packages/eui/src/components/header/header_links/__snapshots__/header_link.test.tsx.snap b/packages/eui/src/components/header/header_links/__snapshots__/header_link.test.tsx.snap
index 7a3456351f1..9e1e22d9e13 100644
--- a/packages/eui/src/components/header/header_links/__snapshots__/header_link.test.tsx.snap
+++ b/packages/eui/src/components/header/header_links/__snapshots__/header_link.test.tsx.snap
@@ -2,7 +2,7 @@
exports[`EuiHeaderLink can render as specific color 1`] = `