Skip to content

Commit

Permalink
fix(Input): Style update: Fix HelpLink position on inputs (#1546)
Browse files Browse the repository at this point in the history
  • Loading branch information
moathabuhamad-cengage authored Nov 14, 2024
1 parent ccbb461 commit fbae9ce
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/fix-input-help-link.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-magma-dom': patch
---

fix(Input): Style update: Fix HelpLink position on inputs.
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const StyledFormFieldContainer = styled.div<{
// Input and helper text <div> wrapper based on labelPosition.
const StyledInputWrapper = styled.div`
flex: 1 1 auto;
align-self: center;
`;

// If the labelPosition is set to 'left' then a <div> wraps the Input, errorMessage, helperMessage, and CharacterCounter for proper styling alignment.
Expand Down
19 changes: 18 additions & 1 deletion packages/react-magma-dom/src/components/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IconButton } from '../IconButton';
import { InputIconPosition, InputSize, InputType } from '../InputBase';
import { LabelPosition } from '../Label';
import { Tooltip } from '../Tooltip';
import { Spacer } from '../Spacer';

const Template: Story<InputProps> = args => (
<>
Expand Down Expand Up @@ -62,6 +63,18 @@ export default {
options: InputType,
},
},
labelText: {
control: 'text',
description: 'Label for the input',
},
helperMessage: {
control: 'text',
description: 'Helper message displayed below the input',
},
errorMessage: {
control: 'text',
description: 'Error message displayed below the input',
},
},
errorMessage: '',
} as Meta;
Expand Down Expand Up @@ -183,7 +196,7 @@ export const HelpLink = args => {
/>
</Tooltip>
</Input>
<br />
<Spacer size={16}/>
<Input
labelText="Help link - left"
labelPosition={LabelPosition.left}
Expand All @@ -200,6 +213,7 @@ export const HelpLink = args => {
/>
</Tooltip>
</Input>
<Spacer size={16}/>
<Input
labelText="Help link - hidden"
isLabelVisuallyHidden
Expand All @@ -221,6 +235,9 @@ export const HelpLink = args => {
};
HelpLink.args = {
...Default.args,
errorMessage: '',
helperMessage: 'Helper Message',
labelText: 'Label Text',
};
HelpLink.parameters = {
controls: { exclude: ['isInverse', 'type', 'iconPosition','isLabelVisuallyHidden','labelPosition' ] },
Expand Down
84 changes: 77 additions & 7 deletions packages/react-magma-dom/src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,75 @@ import { useGenerateId } from '../../utils';
import {
FormFieldContainer,
FormFieldContainerBaseProps,
FormFieldContainerProps,
} from '../FormFieldContainer';
import { InputBase, InputBaseProps, InputSize } from '../InputBase';
import {
getHelpIconButtonSize,
InputBase,
InputBaseProps,
InputSize,
isLeftOrHidden,
} from '../InputBase';
import { LabelPosition } from '../Label';
import styled from '@emotion/styled';
import { ThemeContext } from '../../theme/ThemeContext';
import { Theme } from '@emotion/react';

const getLabelStyles = (
props: FormFieldContainerProps &
React.RefAttributes<HTMLDivElement> & { theme?: Theme } & {
labelPosition?: LabelPosition;
InputSize?: InputSize;
} & { theme: Theme }
) => {
const marginBlock = isLeftOrHidden(props)
? '0'
: `0 ${props.theme.spaceScale.spacing03}`;
const marginInline = isLeftOrHidden(props)
? `0 ${props.theme.spaceScale.spacing03}`
: '0';
const maxWidth = isLeftOrHidden(props)
? 'auto'
: `calc(100% - ${getHelpIconButtonSize(props)} - ${
props.theme.spaceScale.spacing03
})`;
let minHeight: string;
if (props.labelPosition === LabelPosition.left) {
minHeight =
props.InputSize === InputSize.large
? props.theme.spaceScale.spacing11
: props.theme.spaceScale.spacing09;
} else {
minHeight = 'auto';
}
const justifyContent = isLeftOrHidden(props) ? 'end' : 'start';

return { marginBlock, marginInline, maxWidth, minHeight, justifyContent };
};

const StyledFormFieldContainer = styled(FormFieldContainer)<{
labelPosition?: LabelPosition;
InputSize?: InputSize;
}>`
position: relative;
align-items: start;
label {
${props => {
const { marginBlock, marginInline, maxWidth, minHeight, justifyContent } =
getLabelStyles(props);
return `
margin-block: ${marginBlock};
margin-inline: ${marginInline};
max-width: ${maxWidth};
min-height: ${minHeight};
justify-content: ${justifyContent};
`;
}}
display: flex;
align-items: center;
}
`;

export interface InputProps
extends Omit<FormFieldContainerBaseProps, 'fieldId'>,
Expand Down Expand Up @@ -46,14 +113,17 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(

const maxCharacters = typeof maxCount === 'number' ? maxCount : maxLength;

const maxLengthNum = !hasCharacterCounter && maxLength ? maxLength : undefined;
const maxLengthNum =
!hasCharacterCounter && maxLength ? maxLength : undefined;

const isInverse = useIsInverse(props.isInverse);

const [characterLength, setCharacterLength] = useState(
value?.toString().length
);

const theme = React.useContext(ThemeContext);

React.useEffect(() => {
setCharacterLength(value?.toString().length);
}, [value]);
Expand All @@ -71,7 +141,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
}

return (
<FormFieldContainer
<StyledFormFieldContainer
containerStyle={containerStyle}
errorMessage={errorMessage}
fieldId={id}
Expand All @@ -90,12 +160,12 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
maxCount={maxCount}
messageStyle={messageStyle}
testId={testId && `${testId}-formFieldContainer`}
theme={theme}
InputSize={inputSize}
>
<InputBase
{...other}
aria-describedby={
descriptionId ?? props['aria-describedby']
}
aria-describedby={descriptionId ?? props['aria-describedby']}
aria-invalid={!!errorMessage}
hasError={
!!errorMessage ||
Expand All @@ -119,7 +189,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
>
{children}
</InputBase>
</FormFieldContainer>
</StyledFormFieldContainer>
);
}
);
14 changes: 7 additions & 7 deletions packages/react-magma-dom/src/components/InputBase/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ function getHelpLinkSVGSize(props) {
return `${theme.iconSizes.small}px`;
}

function getHelpIconButtonSize(props) {
export function getHelpIconButtonSize(props) {
const { inputSize, theme } = props;

if (inputSize === InputSize.large) {
Expand Down Expand Up @@ -570,7 +570,7 @@ function getIconSize(
}
}

const isLeftOrHidden = ({
export const isLeftOrHidden = ({
labelPosition,
isLabelVisuallyHidden,
}: {
Expand All @@ -584,16 +584,15 @@ export const HelpLinkContainer = styled.span<{
theme: ThemeInterface;
isLabelVisuallyHidden?: boolean;
}>`
position: relative;
position: ${props => (isLeftOrHidden(props) ? 'relative' : 'absolute')};
display: flex;
align-items: center;
justify-content: center;
height: ${props => (isLeftOrHidden(props) ? 'auto' : 'fit-content')};
margin-inline-start: ${props =>
isLeftOrHidden(props) ? `${props.theme.spaceScale.spacing03}` : 0};
transform: translate(
${props => (isLeftOrHidden(props) ? '0' : '-100%')},
isLeftOrHidden(props) ? `${props.theme.spaceScale.spacing03}` : 'auto'};
transform: translateY(
${props =>
isLeftOrHidden(props)
? '0'
Expand All @@ -604,9 +603,10 @@ export const HelpLinkContainer = styled.span<{
width: ${props => getHelpLinkSVGSize(props)};
}
button {
height: ${props => getHelpIconButtonSize(props)};
height: ${props => getHelpIconButtonSize(props)};
width: ${props => getHelpIconButtonSize(props)};
}
inset-inline-end: ${props => (isLeftOrHidden(props) ? 'auto' : '0')};
`;

export const InputBase = React.forwardRef<HTMLInputElement, InputBaseProps>(
Expand Down
47 changes: 31 additions & 16 deletions website/react-magma-docs/src/pages/api/input.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ export function Example() {
icon={<MailOutlineIcon />}
type={InputType.email}
/>

<Input
labelText="Large input with clickable icon on right"
iconAriaLabel="Calendar"
Expand All @@ -297,7 +296,6 @@ export function Example() {
}}
icon={<EventIcon />}
/>

<Input
errorMessage="Error"
inputSize="large"
Expand Down Expand Up @@ -396,6 +394,7 @@ export function Example() {

Some inputs require more content next to the form field, such as a help link to provide a bit of explanation to the user.
If you pass children to the input field, it will render immediately after the input. the placement of the content will vary based on the label's position:

- When the label is positioned at the top, the help link will appear at the top right of the input.
- When the label is positioned on the left, the help link will appear to the right of the input.
- When the label is visually hidden, the help link will appear to the right of the input.
Expand All @@ -404,7 +403,15 @@ The container uses a flex layout to ensure the content is positioned appropriate

```tsx
import React from 'react';
import { IconButton, Input, Tooltip, InputType } from 'react-magma-dom';
import {
IconButton,
Input,
Tooltip,
Spacer,
LabelPosition,
ButtonSize,
ButtonVariant,
} from 'react-magma-dom';
import { HelpIcon } from 'react-magma-icons';
export function Example() {
const helpLinkLabel = 'Learn more';
Expand All @@ -414,40 +421,48 @@ export function Example() {

return (
<>
<Input labelText="Help link - top label" labelPosition="top">
<Input
labelText="Help link - top label"
labelPosition={LabelPosition.top}
>
<Tooltip content={helpLinkLabel}>
<IconButton
aria-label={helpLinkLabel}
icon={<HelpIcon />}
onClick={onHelpLinkClick}
type={InputType.button}
size="small"
variant="link"
size={ButtonSize.small}
variant={ButtonVariant.link}
/>
</Tooltip>
</Input>
<Spacer size="12" />
<Input labelText="Help link - left label" labelPosition="left">
<Spacer size="16" />
<Input
labelText="Help link - left label"
labelPosition={LabelPosition.left}
>
<Tooltip content={helpLinkLabel}>
<IconButton
aria-label={helpLinkLabel}
icon={<HelpIcon />}
onClick={onHelpLinkClick}
type={InputType.button}
size="small"
variant="link"
size={ButtonSize.small}
variant={ButtonVariant.link}
/>
</Tooltip>
</Input>
<Input labelText="Help link - Hidden" isLabelVisuallyHidden helperMessage="Help link - Label Hidden">
<Spacer size="16" />
<Input
labelText="Help link - Hidden"
isLabelVisuallyHidden
helperMessage="Help link - Label Hidden"
>
<Tooltip content={helpLinkLabel}>
<IconButton
aria-label={helpLinkLabel}
icon={<HelpIcon />}
onClick={onHelpLinkClick}
type={InputType.button}
size="small"
variant="link"
size={ButtonSize.small}
variant={ButtonVariant.link}
/>
</Tooltip>
</Input>
Expand Down

2 comments on commit fbae9ce

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.