Skip to content

Commit

Permalink
fix(form): ensure any custom margin-bottom applied to inputs override…
Browse files Browse the repository at this point in the history
… fieldSpacing

Replaces the previous implementation which targeted `FormField` and `Fieldset`
in the `Form` styles to apply the given `fieldSpacing` value. This prevented any
custom values being set on an input when it was rendered as a child of `Form`.
`FormSpacingProvider`, `FormContext` and a `addFormSpacing` util have been
added to support applying the field spacing on a child that has not been passed
a custom margin value.

fix #5681
  • Loading branch information
edleeks87 committed Mar 7, 2023
1 parent 681a284 commit 96a1222
Show file tree
Hide file tree
Showing 33 changed files with 782 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const CheckableInput = React.forwardRef(
reverse={reverse}
>
<InputBehaviour>
<FormField {...formFieldProps}>
<FormField {...formFieldProps} my={0}>
<StyledCheckableInput>
<HiddenCheckableInput {...inputProps} />
{children}
Expand Down
72 changes: 41 additions & 31 deletions src/__internal__/fieldset/fieldset.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "./fieldset.style";
import ValidationIcon from "../validations/validation-icon.component";
import { InputGroupBehaviour, InputGroupContext } from "../input-behaviour";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";

export interface FieldsetProps extends MarginProps {
/** Role */
Expand Down Expand Up @@ -55,36 +56,45 @@ const Fieldset = ({
isRequired,
blockGroupBehaviour,
...rest
}: FieldsetProps) => (
<InputGroupBehaviour blockGroupBehaviour={blockGroupBehaviour}>
<StyledFieldset data-component="fieldset" m={0} {...rest}>
{legend && (
<InputGroupContext.Consumer>
{({ onMouseEnter, onMouseLeave }) => (
<StyledLegend
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
inline={inline}
width={legendWidth}
align={legendAlign}
rightPadding={legendSpacing}
>
<StyledLegendContent isRequired={isRequired}>
{legend}
<ValidationIcon
error={error}
warning={warning}
info={info}
tooltipFlipOverrides={["top", "bottom"]}
/>
</StyledLegendContent>
</StyledLegend>
)}
</InputGroupContext.Consumer>
)}
{children}
</StyledFieldset>
</InputGroupBehaviour>
);
}: FieldsetProps) => {
const marginProps = useFormSpacing(rest);

return (
<InputGroupBehaviour blockGroupBehaviour={blockGroupBehaviour}>
<StyledFieldset
data-component="fieldset"
m={0}
{...marginProps}
{...rest}
>
{legend && (
<InputGroupContext.Consumer>
{({ onMouseEnter, onMouseLeave }) => (
<StyledLegend
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
inline={inline}
width={legendWidth}
align={legendAlign}
rightPadding={legendSpacing}
>
<StyledLegendContent isRequired={isRequired}>
{legend}
<ValidationIcon
error={error}
warning={warning}
info={info}
tooltipFlipOverrides={["top", "bottom"]}
/>
</StyledLegendContent>
</StyledLegend>
)}
</InputGroupContext.Consumer>
)}
{children}
</StyledFieldset>
</InputGroupBehaviour>
);
};

export default Fieldset;
6 changes: 2 additions & 4 deletions src/__internal__/form-field/form-field.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { MarginProps } from "styled-system";
import invariant from "invariant";

import { ValidationProps } from "../validations";
import { filterStyledSystemMarginProps } from "../../style/utils";
import FormFieldStyle, { FieldLineStyle } from "./form-field.style";
import Label from "../label";
import FieldHelp from "../field-help";
import tagComponent, { TagProps } from "../utils/helpers/tags/tags";
import { TabContext, TabContextProps } from "../../components/tabs/tab";
import useIsAboveBreakpoint from "../../hooks/__internal__/useIsAboveBreakpoint";
import { IconType } from "../../components/icon";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";

interface CommonFormFieldProps extends MarginProps, ValidationProps {
/** If true, the component will be disabled */
Expand Down Expand Up @@ -132,7 +132,7 @@ const FormField = ({
const { setError, setWarning, setInfo } = useContext<TabContextProps>(
TabContext
);

const marginProps = useFormSpacing(rest);
const isMounted = useRef(false);

useLayoutEffect(() => {
Expand All @@ -157,8 +157,6 @@ const FormField = ({
};
}, [id, setError, setWarning, setInfo, error, warning, info]);

const marginProps = filterStyledSystemMarginProps(rest);

const fieldHelp = fieldHelpContent ? (
<FieldHelp
labelInline={inlineLabel}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

export interface FormSpacingContextProps {
marginBottom?: string;
}

export const FormSpacingContext = React.createContext<FormSpacingContextProps>(
{}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import {
FormSpacingContext,
FormSpacingContextProps,
} from "./form-spacing-context";

interface FormSpacingProviderProps extends FormSpacingContextProps {
children: React.ReactNode;
}

const FormSpacingProvider = ({
marginBottom,
children,
}: FormSpacingProviderProps) => (
<FormSpacingContext.Provider value={{ marginBottom }}>
{children}
</FormSpacingContext.Provider>
);

export default FormSpacingProvider;
3 changes: 3 additions & 0 deletions src/__internal__/form-spacing-provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { FormSpacingContext } from "./form-spacing-context";
export type { FormSpacingContextProps } from "./form-spacing-context";
export { default } from "./form-spacing-provider.component";
5 changes: 4 additions & 1 deletion src/components/checkbox/checkbox-group.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Fieldset from "../../__internal__/fieldset";
import { filterStyledSystemMarginProps } from "../../style/utils";
import { TooltipProvider } from "../../__internal__/tooltip-provider";
import { ValidationProps } from "../../__internal__/validations";
import FormSpacingProvider from "../../__internal__/form-spacing-provider";

export interface CheckboxGroupProps extends ValidationProps, MarginProps {
/** The content for the CheckboxGroup Legend */
Expand Down Expand Up @@ -72,7 +73,9 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
info: !!info,
}}
>
{children}
<FormSpacingProvider marginBottom={undefined}>
{children}
</FormSpacingProvider>
</CheckboxGroupContext.Provider>
</StyledCheckboxGroup>
</Fieldset>
Expand Down
14 changes: 9 additions & 5 deletions src/components/checkbox/checkbox.component.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useContext } from "react";
import { MarginProps } from "styled-system";

import CheckboxStyle from "./checkbox.style";
import CheckableInput, {
CommonCheckableInputProps,
} from "../../__internal__/checkable-input/checkable-input.component";
import CheckboxSvg from "./checkbox-svg.component";
import useIsAboveBreakpoint from "../../hooks/__internal__/useIsAboveBreakpoint";
import { filterStyledSystemMarginProps } from "../../style/utils";
import { TooltipProvider } from "../../__internal__/tooltip-provider";
import { CheckboxGroupContext } from "./checkbox-group.component";
import Logger from "../../__internal__/utils/logger";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";

export interface CheckboxProps extends CommonCheckableInputProps, MarginProps {
/** Breakpoint for adaptive spacing (left margin changes to 0). Enables the adaptive behaviour when set */
Expand Down Expand Up @@ -72,19 +73,20 @@ export const Checkbox = React.forwardRef(
"data-role": dataRole,
helpAriaLabel,
inputRef,
...props
...rest
}: CheckboxProps,
ref: React.ForwardedRef<HTMLInputElement>
) => {
const largeScreen = useIsAboveBreakpoint(adaptiveSpacingBreakpoint);
const adaptiveSpacingSmallScreen = !!(
adaptiveSpacingBreakpoint && !largeScreen
);
const checkboxGroupContext = useContext(CheckboxGroupContext);
const {
error: contextError,
warning: contextWarning,
info: contextInfo,
} = useContext(CheckboxGroupContext);
} = checkboxGroupContext;

if (!deprecateInputRefWarnTriggered && inputRef) {
deprecateInputRefWarnTriggered = true;
Expand Down Expand Up @@ -120,9 +122,11 @@ export const Checkbox = React.forwardRef(
labelWidth,
tooltipPosition,
ref: ref || inputRef,
...props,
...rest,
};

const marginProps = useFormSpacing(rest);

return (
<TooltipProvider
helpAriaLabel={helpAriaLabel}
Expand All @@ -142,7 +146,7 @@ export const Checkbox = React.forwardRef(
fieldHelpInline={fieldHelpInline}
reverse={reverse}
size={size}
{...filterStyledSystemMarginProps(props)}
{...marginProps}
>
<CheckableInput {...inputProps}>
<CheckboxSvg />
Expand Down
2 changes: 2 additions & 0 deletions src/components/date-range/date-range.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ const DateRange = ({
value={{ inputRefMap, setInputRefMap: updateInputMap }}
>
<DateInput
my={0} // prevents any form spacing being applied
{...dateProps("start")}
onFocus={() => handleFocus("end")}
data-element="start-date"
Expand All @@ -263,6 +264,7 @@ const DateRange = ({
ref={startRef}
/>
<DateInput
my={0} // prevents any form spacing being applied
{...dateProps("end")}
onFocus={() => handleFocus("start")}
data-element="end-date"
Expand Down
6 changes: 5 additions & 1 deletion src/components/date/date.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import DatePicker from "./__internal__/date-picker";
import DateRangeContext from "../date-range/date-range.context";
import useClickAwayListener from "../../hooks/__internal__/useClickAwayListener";
import Logger from "../../__internal__/utils/logger";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";

const marginPropTypes = filterStyledSystemMarginProps(
styledSystemPropTypes.space
Expand Down Expand Up @@ -358,6 +359,8 @@ const DateInput = React.forwardRef(
return value;
};

const marginProps = useFormSpacing(rest);

return (
<StyledDateInput
ref={wrapperRef}
Expand All @@ -367,7 +370,7 @@ const DateInput = React.forwardRef(
data-component={dataComponent || "date"}
data-element={dataElement}
data-role={dataRole}
{...filterStyledSystemMarginProps(rest)}
{...marginProps}
applyDateRangeStyling={!!inputRefMap}
>
<Textbox
Expand All @@ -392,6 +395,7 @@ const DateInput = React.forwardRef(
size={size}
disabled={disabled}
readOnly={readOnly}
m={0}
/>
<DatePicker
disablePortal={disablePortal}
Expand Down
4 changes: 3 additions & 1 deletion src/components/fieldset/__snapshots__/fieldset.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ exports[`Fieldset renders correctly 1`] = `
data-component="fieldset-style"
inline={false}
>
<Textbox />
<FormSpacingProvider>
<Textbox />
</FormSpacingProvider>
</styled.div>
</styled.fieldset>
</ContextProvider>
Expand Down
11 changes: 8 additions & 3 deletions src/components/fieldset/fieldset.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import React from "react";
import { MarginProps } from "styled-system";

import tagComponent from "../../__internal__/utils/helpers/tags/tags";
import { filterStyledSystemMarginProps } from "../../style/utils";
import {
FieldsetStyle,
LegendContainerStyle,
FieldsetContentStyle,
StyledFieldsetProps,
} from "./fieldset.style";
import { NewValidationContext } from "../carbon-provider/carbon-provider.component";
import FormSpacingProvider from "../../__internal__/form-spacing-provider";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";

export interface FieldsetProps extends StyledFieldsetProps, MarginProps {
/** Child elements */
Expand All @@ -34,17 +35,21 @@ export const Fieldset = ({
);
};

const marginProps = useFormSpacing(rest);

return (
<NewValidationContext.Provider value={{ validationRedesignOptIn: false }}>
<FieldsetStyle
{...tagComponent("fieldset", rest)}
{...rest}
m={0}
{...filterStyledSystemMarginProps(rest)}
{...marginProps}
>
<FieldsetContentStyle data-component="fieldset-style" inline={inline}>
{getLegend()}
{children}
<FormSpacingProvider marginBottom={undefined}>
{children}
</FormSpacingProvider>
</FieldsetContentStyle>
</FieldsetStyle>
</NewValidationContext.Provider>
Expand Down
Loading

0 comments on commit 96a1222

Please sign in to comment.