diff --git a/packages/eui/changelogs/upcoming/9328.md b/packages/eui/changelogs/upcoming/9328.md new file mode 100644 index 000000000000..3b8d4622ebe0 --- /dev/null +++ b/packages/eui/changelogs/upcoming/9328.md @@ -0,0 +1,2 @@ +- Added `isLoading` prop on `EuiFormControlButton` + diff --git a/packages/eui/src/components/form/form_control_button/form_control_button.stories.tsx b/packages/eui/src/components/form/form_control_button/form_control_button.stories.tsx index 2e153c4412de..475a5b2e18a1 100644 --- a/packages/eui/src/components/form/form_control_button/form_control_button.stories.tsx +++ b/packages/eui/src/components/form/form_control_button/form_control_button.stories.tsx @@ -37,6 +37,7 @@ const meta: Meta = { value: '', isDisabled: false, isInvalid: false, + isLoading: false, compressed: false, fullWidth: true, }, diff --git a/packages/eui/src/components/form/form_control_button/form_control_button.styles.ts b/packages/eui/src/components/form/form_control_button/form_control_button.styles.ts index 7f1d0f370002..fc22953abaf1 100644 --- a/packages/eui/src/components/form/form_control_button/form_control_button.styles.ts +++ b/packages/eui/src/components/form/form_control_button/form_control_button.styles.ts @@ -9,11 +9,16 @@ import { css } from '@emotion/react'; import { UseEuiTheme } from '@elastic/eui-theme-common'; -import { logicalCSS } from '../../../global_styling'; -import { euiFormControlStyles, euiFormPlaceholderStyles } from '../form.styles'; +import { euiDisabledSelector, logicalCSS } from '../../../global_styling'; +import { + euiFormControlStyles, + euiFormPlaceholderStyles, + euiFormVariables, +} from '../form.styles'; export const euiFormControlButtonStyles = (euiThemeContext: UseEuiTheme) => { const { euiTheme } = euiThemeContext; + const form = euiFormVariables(euiThemeContext); const formStyles = euiFormControlStyles(euiThemeContext); return { @@ -50,6 +55,15 @@ export const euiFormControlButtonStyles = (euiThemeContext: UseEuiTheme) => { compressed: css` ${formStyles.compressed} `, + isLoading: css` + &:is(${euiDisabledSelector}) { + background-color: ${form.backgroundColor}; + } + + .euiLoadingSpinner { + color: ${euiTheme.colors.borderBasePlain}; + } + `, formWidth: formStyles.formWidth, fullWidth: css(formStyles.fullWidth), euiFormControlButton__content: css` diff --git a/packages/eui/src/components/form/form_control_button/form_control_button.test.tsx b/packages/eui/src/components/form/form_control_button/form_control_button.test.tsx index a71447f539c6..d1fa910ef3c8 100644 --- a/packages/eui/src/components/form/form_control_button/form_control_button.test.tsx +++ b/packages/eui/src/components/form/form_control_button/form_control_button.test.tsx @@ -127,6 +127,21 @@ describe('EuiButtonEmpty', () => { }); }); + describe('isLoading', () => { + it('is rendered', () => { + const { getByTestSubject } = render( + + ); + + const classes = Object.values( + getByTestSubject('euiFormControlButton').classList + ); + + expect(getByTestSubject('euiFormControlButton')).toBeDisabled(); + expect(classes.some((clx) => clx.includes('isLoading'))).toBe(true); + }); + }); + describe('isInvalid', () => { it('is rendered', () => { const { getByTestSubject } = render( diff --git a/packages/eui/src/components/form/form_control_button/form_control_button.tsx b/packages/eui/src/components/form/form_control_button/form_control_button.tsx index 06a070d82f8c..3f0bdaaeba98 100644 --- a/packages/eui/src/components/form/form_control_button/form_control_button.tsx +++ b/packages/eui/src/components/form/form_control_button/form_control_button.tsx @@ -48,7 +48,7 @@ export type EuiFormControlButtonInputProps = { export type EuiFormControlButtonProps = EuiFormControlButtonInputProps & Omit< EuiButtonEmptyProps, - 'value' | 'color' | 'size' | 'flush' | 'isSelected' | 'isLoading' + 'value' | 'color' | 'size' | 'flush' | 'isSelected' > & { /** * Defines the button label when used like an input in combination with `placeholder` @@ -69,6 +69,8 @@ export const EuiFormControlButton: FunctionComponent< isDisabled: _isDisabled, isInvalid: _isInvalid, fullWidth = true, + iconSide, + isLoading: _isLoading, href, rel, // required by our local href-with-rel eslint rule ...rest @@ -78,12 +80,14 @@ export const EuiFormControlButton: FunctionComponent< const { isDisabled: formLayoutIsDisabled, isInvalid: formLayoutIsInvalid, + isLoading: formLayoutIsLoading, readOnly: formLayoutReadOnly, compressed: formLayoutCompressed, } = useContext(EuiFormControlLayoutContext); const isDisabled = _isDisabled ?? formLayoutIsDisabled; const isInvalid = _isInvalid ?? formLayoutIsInvalid; + const isLoading = formLayoutIsLoading === true ? false : _isLoading; const compressed = _compressed ?? formLayoutCompressed; const styles = useEuiMemoizedStyles(euiFormControlButtonStyles); @@ -92,6 +96,7 @@ export const EuiFormControlButton: FunctionComponent< const cssStyles = [ styles.euiFormControlButton, isInvalid && styles.isInvalid, + isLoading && styles.isLoading, formLayoutReadOnly && styles.readOnly, compressed && styles.compressed, fullWidth ? styles.fullWidth : styles.formWidth, @@ -145,6 +150,8 @@ export const EuiFormControlButton: FunctionComponent< textProps={false} color="text" isDisabled={isDisabled} + isLoading={isLoading} + iconSide={isLoading ? 'right' : iconSide} {...restProps} > {hasText && ( 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 2575dc1c5e35..03ecd870b5e4 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 @@ -176,6 +176,7 @@ export const EuiFormControlLayout: FunctionComponent< isDisabled: isDisabled, isInvalid: isInvalid, readOnly: readOnly, + isLoading: isLoading, }} > ; /** @@ -23,6 +28,7 @@ export const EuiFormControlLayoutContext = inputId: '', isDisabled: false, isInvalid: false, + isLoading: false, readOnly: false, });