Skip to content

Commit

Permalink
Fix various EuiFormControlLayout usages (elastic#192779)
Browse files Browse the repository at this point in the history
## Summary

This is a follow up to EUI's Emotion conversion of
**EuiFormControlLayout/Delimited** (see
elastic#190752,
elastic/eui#7954, and
elastic/eui#7957).

> [!note]
> Please manually QA your team's affected form control(s) to confirm
they still look and behave as expected and are non-broken. The EUI team
is not familiar enough with each plugin's setups to pull down and QA
this PR ourselves.

While QA testing the upgrade, I noticed a few incorrect usages of
**EuiFormControlLayout** but wanted to wait until after the upgrade to
push out fixes (to prevent delaying the PR further). In general, here is
EUI's [recommended usage of the
component](https://eui.elastic.co/#/forms/form-controls#form-control-layout):

- Where possible, **simply don't use it**. Almost all form controls are
**already** automatically wrapped in any EuiFormControlLayout by
default, and should accept a large majority of the props that the layout
accepts.
- If you **must** use it, set the `controlOnly` prop on the child
input/control to avoid buggy styling (e.g. duplicate borders).
- If you can't do either of the above for any reason (e.g. missing prop
support), reach out to the EUI team to ask for your UX as a feature
request!

### Checklist

Delete any items that are not applicable to this PR.

- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
  • Loading branch information
cee-chen authored Sep 24, 2024
1 parent 4c3865d commit fd7b86e
Show file tree
Hide file tree
Showing 18 changed files with 321 additions and 475 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiFormControlLayout,
EuiFormRow,
EuiSwitch,
EuiTextArea,
Expand Down Expand Up @@ -128,48 +127,46 @@ export const SavedBookEditor = ({
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiFormControlLayout>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.authorLabel', {
defaultMessage: 'Author',
})}
>
<EuiFieldText
value={authorName ?? ''}
onChange={(e) => attributesManager.authorName.next(e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.titleLabel', {
defaultMessage: 'Title',
})}
>
<EuiFieldText
value={bookTitle ?? ''}
onChange={(e) => attributesManager.bookTitle.next(e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.pagesLabel', {
defaultMessage: 'Number of pages',
})}
>
<EuiFieldNumber
value={numberOfPages ?? ''}
onChange={(e) => attributesManager.numberOfPages.next(+e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.synopsisLabel', {
defaultMessage: 'Synopsis',
})}
>
<EuiTextArea
value={synopsis ?? ''}
onChange={(e) => attributesManager.bookSynopsis.next(e.target.value)}
/>
</EuiFormRow>
</EuiFormControlLayout>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.authorLabel', {
defaultMessage: 'Author',
})}
>
<EuiFieldText
value={authorName ?? ''}
onChange={(e) => attributesManager.authorName.next(e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.titleLabel', {
defaultMessage: 'Title',
})}
>
<EuiFieldText
value={bookTitle ?? ''}
onChange={(e) => attributesManager.bookTitle.next(e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.pagesLabel', {
defaultMessage: 'Number of pages',
})}
>
<EuiFieldNumber
value={numberOfPages ?? ''}
onChange={(e) => attributesManager.numberOfPages.next(+e.target.value)}
/>
</EuiFormRow>
<EuiFormRow
label={i18n.translate('embeddableExamples.savedBook.editor.synopsisLabel', {
defaultMessage: 'Synopsis',
})}
>
<EuiTextArea
value={synopsis ?? ''}
onChange={(e) => attributesManager.bookSynopsis.next(e.target.value)}
/>
</EuiFormRow>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
margin-top: $euiSizeS;
}

.lnsConfigPanelNoPadding {
padding: 0;
}

.lnsConfigPanelDate__label {
min-width: 56px; // makes both labels ("from" and "to") the same width
.lnsConfigPanelAnnotations__date .euiFormControlLayout__prepend {
min-width: $euiSize * 3.25; // makes both labels ("from" and "to") the same width
}

.lnsConfigPanelAnnotations__addButton {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,7 @@

import { i18n } from '@kbn/i18n';
import React from 'react';
import {
EuiFormRow,
EuiSwitch,
EuiText,
EuiFormControlLayout,
EuiFormLabel,
EuiDatePicker,
} from '@elastic/eui';
import { EuiFormRow, EuiSwitch, EuiText, EuiDatePicker } from '@elastic/eui';
import moment from 'moment';
import type {
PointInTimeEventAnnotationConfig,
Expand Down Expand Up @@ -107,36 +100,23 @@ export const ConfigPanelRangeDatePicker = ({
dataTestSubj?: string;
}) => {
return (
<EuiFormRow display="rowCompressed" fullWidth label={label} className="lnsRowCompressedMargin">
{prependLabel ? (
<EuiFormControlLayout
fullWidth
className="lnsConfigPanelNoPadding"
prepend={
<EuiFormLabel className="lnsConfigPanelDate__label">{prependLabel}</EuiFormLabel>
}
>
<EuiDatePicker
calendarClassName={calendarClassName}
fullWidth
showTimeSelect
selected={value}
onChange={onChange}
dateFormat="MMM D, YYYY @ HH:mm:ss.SSS"
data-test-subj={dataTestSubj}
/>
</EuiFormControlLayout>
) : (
<EuiDatePicker
calendarClassName={calendarClassName}
fullWidth
showTimeSelect
selected={value}
onChange={onChange}
dateFormat="MMM D, YYYY @ HH:mm:ss.SSS"
data-test-subj={dataTestSubj}
/>
)}
<EuiFormRow
display="rowCompressed"
fullWidth
label={label}
className="lnsConfigPanelAnnotations__date lnsRowCompressedMargin"
>
<EuiDatePicker
compressed
calendarClassName={calendarClassName}
fullWidth
showTimeSelect
selected={value}
onChange={onChange}
dateFormat="MMM D, YYYY @ HH:mm:ss.SSS"
data-test-subj={dataTestSubj}
prepend={prependLabel}
/>
</EuiFormRow>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
EuiContextMenuPanel,
EuiCopy,
EuiFieldText,
EuiFormControlLayout,
EuiHorizontalRule,
EuiPopover,
EuiSpacer,
Expand All @@ -29,12 +28,24 @@ export interface TokenFieldProps extends Omit<EuiFieldTextProps, 'append'> {
value: string;
}

export const TokenField: FunctionComponent<TokenFieldProps> = (props) => {
export const TokenField: FunctionComponent<TokenFieldProps> = ({ value, ...props }) => {
return (
<EuiFormControlLayout
<EuiFieldText
data-test-subj="apiKeyTokenField"
aria-label={i18n.translate('xpack.security.copyTokenField.tokenLabel', {
defaultMessage: 'Token',
})}
value={value}
style={{
fontFamily: euiThemeVars.euiCodeFontFamily,
fontSize: euiThemeVars.euiFontSizeXS,
backgroundColor: 'transparent',
}}
onFocus={(event) => event.currentTarget.select()}
readOnly
{...props}
append={
<EuiCopy textToCopy={props.value}>
<EuiCopy textToCopy={value}>
{(copyText) => (
<EuiButtonIcon
aria-label={i18n.translate('xpack.security.copyTokenField.copyButton', {
Expand All @@ -48,25 +59,7 @@ export const TokenField: FunctionComponent<TokenFieldProps> = (props) => {
)}
</EuiCopy>
}
style={{ backgroundColor: 'transparent' }}
readOnly
>
<EuiFieldText
data-test-subj="apiKeyTokenField"
controlOnly
aria-label={i18n.translate('xpack.security.copyTokenField.tokenLabel', {
defaultMessage: 'Token',
})}
value={props.value}
style={{
fontFamily: euiThemeVars.euiCodeFontFamily,
fontSize: euiThemeVars.euiFontSizeXS,
backgroundColor: 'transparent',
}}
onFocus={(event) => event.currentTarget.select()}
readOnly
/>
</EuiFormControlLayout>
/>
);
};

Expand Down Expand Up @@ -118,7 +111,7 @@ export const SelectableTokenField: FunctionComponent<SelectableTokenFieldProps>
closePopover={closePopover}
>
<EuiContextMenuPanel
initialFocusedItemIndex={selectedIndex * 2}
initialFocusedItemIndex={selectedIndex}
items={options.reduce<ReactElement[]>((items, option, i) => {
items.push(
<EuiContextMenuItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const AddDomainForm: React.FC = () => {
fullWidth
>
<EuiFieldText
controlOnly
autoFocus
value={addDomainFormInputValue}
onChange={(e) => setAddDomainFormInputValue(e.target.value)}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fd7b86e

Please sign in to comment.