Skip to content

Commit

Permalink
[EuiForm] specify default fullWidth with root component (#6229)
Browse files Browse the repository at this point in the history
Co-authored-by: Constance <constancecchen@users.noreply.github.com>
  • Loading branch information
Spencer and Constance committed Sep 28, 2022
1 parent c0b90a4 commit 1e90096
Show file tree
Hide file tree
Showing 36 changed files with 736 additions and 152 deletions.
6 changes: 4 additions & 2 deletions scripts/jest/setup/throw_on_console_error.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { format } from 'util'

// Fail if a test ends up `console.error`-ing, e.g. if React logs because of a
// failed prop types check.
console.error = (message) => {
console.error = (message, ...rest) => {
// @see https://github.com/emotion-js/emotion/issues/1105
// This error that Emotion throws doesn't apply to Jest, so
// we're just going to straight up ignore the first/nth-child warning
Expand All @@ -14,5 +16,5 @@ console.error = (message) => {
return;
}

throw new Error(message);
throw new Error(format(message, ...rest));
};
28 changes: 28 additions & 0 deletions src-docs/src/views/form_layouts/form_layouts_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const describedFormGroupRatioSource = require('!!raw-loader!./described_form_gro
import FullWidth from './full_width';
const fullWidthSource = require('!!raw-loader!./full_width');

import FullWidthViaContext from './full_width_via_context';
const fullWidthViaContextSource = require('!!raw-loader!./full_width_via_context');

import Inline from './inline';
const inlineSource = require('!!raw-loader!./inline');

Expand Down Expand Up @@ -130,6 +133,31 @@ export const FormLayoutsExample = {
>
<EuiRange fullWidth />
</EuiFormRow>`,
},
{
title: 'Global full-width',
text: (
<p>
To set all the row and controls in a form to{' '}
<EuiCode>fullWidth</EuiCode>, specify the prop on the root{' '}
<EuiCode>EuiForm</EuiCode> component.
</p>
),
props: {
EuiForm,
},
demo: <FullWidthViaContext />,
source: [
{
type: GuideSectionTypes.JS,
code: fullWidthViaContextSource,
},
],
snippet: `<EuiForm fullWidth>
<EuiFormRow label="Everything defaults to fullWidth={true}" >
<EuiRange />
</EuiFormRow>
</EuiForm>`,
},
{
title: 'Inline',
Expand Down
101 changes: 101 additions & 0 deletions src-docs/src/views/form_layouts/full_width_via_context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';

import {
EuiForm,
EuiFieldSearch,
EuiRange,
EuiTextArea,
EuiFormRow,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiDescribedFormGroup,
EuiSelect,
EuiFilePicker,
EuiButton,
} from '../../../../src/components';

export default () => {
const [range, setRange] = React.useState(42);

return (
<EuiForm
fullWidth
onSubmit={(e) => {
e.preventDefault();
}}
>
<EuiFlexGroup>
<EuiFlexItem>
<EuiFieldSearch
placeholder="Search..."
aria-label="An example of search with fullWidth"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton>Search</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer size="l" />

<EuiFormRow
label="Works on form rows too"
helpText="Note that the fullWidth prop is not passed to any of these elements, it's read from the parent <EuiForm> component."
>
<EuiRange
min={0}
max={100}
name="range"
value={range}
onChange={(e) => {
if (e.target instanceof HTMLInputElement) {
setRange(Number.parseInt(e.target.value, 10));
}
}}
/>
</EuiFormRow>

<EuiSpacer />

<EuiDescribedFormGroup
title={<h3>Works with all form controls and layout components</h3>}
description={
<>
<p>
Any component that supports the <code>fullWidth</code> prop that
is.
</p>
<p>
Make sure it is appropriate at all of the widths that the
container can take. There are many situations where a full-width
form is inappropriate.
</p>
</>
}
>
<EuiFormRow label="Text area">
<EuiTextArea placeholder="" />
</EuiFormRow>
</EuiDescribedFormGroup>

<EuiFormRow label="Works on EuiSelect">
<EuiSelect
options={[
{
value: 'option_one',
text:
'Option one is very long in order to try justifying the use of fullWidth on a select box',
},
{ value: 'option_two', text: 'Option two' },
{ value: 'option_three', text: 'Option three' },
]}
/>
</EuiFormRow>

<EuiFormRow label="It can be disabled for a specific control">
<EuiFilePicker display="default" fullWidth={false} />
</EuiFormRow>
</EuiForm>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ exports[`EuiDescribedFormGroup is rendered 1`] = `
<EuiFormRow
describedByIds={Array []}
display="row"
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
Expand Down Expand Up @@ -81,7 +80,6 @@ exports[`EuiDescribedFormGroup props description is not rendered when it's not p
<EuiFormRow
describedByIds={Array []}
display="row"
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
Expand Down Expand Up @@ -181,7 +179,6 @@ exports[`EuiDescribedFormGroup props gutterSize is rendered 1`] = `
<EuiFormRow
describedByIds={Array []}
display="row"
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
Expand Down Expand Up @@ -232,7 +229,6 @@ exports[`EuiDescribedFormGroup props props for the flex item containers are pass
<EuiFormRow
describedByIds={Array []}
display="row"
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
Expand Down Expand Up @@ -332,7 +328,6 @@ exports[`EuiDescribedFormGroup props titleSize is rendered 1`] = `
<EuiFormRow
describedByIds={Array []}
display="row"
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
Expand Down Expand Up @@ -388,7 +383,6 @@ exports[`EuiDescribedFormGroup ties together parts for accessibility 1`] = `
"Error two",
]
}
fullWidth={false}
hasChildLabel={true}
hasEmptyLabelSpace={false}
helpText="Help text"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
*/

import React from 'react';
import { shallow } from 'enzyme';
import { shallow, render } from 'enzyme';
import { requiredProps } from '../../../test';
import { shouldRenderCustomStyles } from '../../../test/internal';

import { EuiForm } from '../form';
import { EuiFormRow } from '../form_row';
import { EuiDescribedFormGroup } from './described_form_group';

Expand Down Expand Up @@ -132,4 +133,24 @@ describe('EuiDescribedFormGroup', () => {
expect(component).toMatchSnapshot();
});
});

describe('inherits', () => {
test('fullWidth from <EuiForm />', () => {
const component = render(
<EuiForm fullWidth>
<EuiDescribedFormGroup {...props} />
</EuiForm>
);

if (
!component
.find('.euiDescribedFormGroup')
.hasClass('euiDescribedFormGroup--fullWidth')
) {
throw new Error(
'expected EuiDescribedFormGroup to inherit fullWidth from EuiForm'
);
}
});
});
});
47 changes: 28 additions & 19 deletions src/components/form/described_form_group/described_form_group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
EuiFlexGroupGutterSize,
EuiFlexItemProps,
} from '../../flex';
import { useFormContext } from '../eui_form_context';

export type EuiDescribedFormGroupProps = CommonProps &
Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
Expand All @@ -29,17 +30,21 @@ export type EuiDescribedFormGroupProps = CommonProps &
children?: ReactNode;
/**
* Passed to `EuiFlexGroup`.
* @default l
*/
gutterSize?: EuiFlexGroupGutterSize;
/**
* Expand to fill 100% of the parent.
* Defaults to `fullWidth` prop of `<EuiForm>`.
* Default max-width is 800px.
* @default false
*/
fullWidth?: boolean;
/**
* Width ratio of description column compared to field column.
* Can be used in conjunction with `fullWidth` and
* may require `fullWidth` to be applied to child elements.
* @default half
*/
ratio?: 'half' | 'third' | 'quarter';
/**
Expand All @@ -48,6 +53,7 @@ export type EuiDescribedFormGroupProps = CommonProps &
title: EuiTitleProps['children'];
/**
* Adjust the visual `size` of the EuiTitle that wraps `title`.
* @default xs
*/
titleSize?: EuiTitleSize;
/**
Expand All @@ -64,19 +70,24 @@ export type EuiDescribedFormGroupProps = CommonProps &
fieldFlexItemProps?: PropsOf<typeof EuiFlexItem>;
};

export const EuiDescribedFormGroup: FunctionComponent<EuiDescribedFormGroupProps> = ({
children,
className,
gutterSize = 'l',
fullWidth = false,
ratio = 'half',
titleSize = 'xs',
title,
description,
descriptionFlexItemProps,
fieldFlexItemProps,
...rest
}) => {
export const EuiDescribedFormGroup: FunctionComponent<EuiDescribedFormGroupProps> = (
props
) => {
const { defaultFullWidth } = useFormContext();

const {
children,
className,
gutterSize = 'l',
fullWidth = defaultFullWidth,
ratio = 'half',
titleSize = 'xs',
title,
description,
descriptionFlexItemProps,
fieldFlexItemProps,
...rest
} = props;
const classes = classNames(
'euiDescribedFormGroup',
{
Expand All @@ -93,18 +104,16 @@ export const EuiDescribedFormGroup: FunctionComponent<EuiDescribedFormGroupProps
let renderedDescription: ReactNode;

if (description) {
// If the description is just a string, wrap it in a paragraph element
if (typeof description === 'string') {
description = <p>{description}</p>;
}

renderedDescription = (
<EuiText
size="s"
color="subdued"
className="euiDescribedFormGroup__description"
>
{description}
{
// If the description is just a string, wrap it in a paragraph element
typeof description === 'string' ? <p>{description}</p> : description
}
</EuiText>
);
}
Expand Down
21 changes: 21 additions & 0 deletions src/components/form/eui_form_context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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';

export interface FormContextValue {
defaultFullWidth: boolean;
}

export const FormContext = React.createContext<FormContextValue>({
defaultFullWidth: false,
});

export function useFormContext() {
return React.useContext(FormContext);
}
19 changes: 19 additions & 0 deletions src/components/form/field_number/field_number.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from 'react';
import { render } from 'enzyme';
import { requiredProps } from '../../../test/required_props';

import { EuiForm } from '../form';
import { EuiFieldNumber } from './field_number';

jest.mock('../form_control_layout', () => {
Expand Down Expand Up @@ -89,4 +90,22 @@ describe('EuiFieldNumber', () => {
});
});
});

describe('inherits', () => {
test('fullWidth from <EuiForm />', () => {
const component = render(
<EuiForm fullWidth>
<EuiFieldNumber />
</EuiForm>
);

if (
!component.find('.euiFieldNumber').hasClass('euiFieldNumber--fullWidth')
) {
throw new Error(
'expected EuiFieldNumber to inherit fullWidth from EuiForm'
);
}
});
});
});
Loading

0 comments on commit 1e90096

Please sign in to comment.