Skip to content

Commit

Permalink
fix(formsection): use grid for form section layout
Browse files Browse the repository at this point in the history
  • Loading branch information
zachpwr committed May 12, 2020
2 parents 9ab0fc6 + f758aa4 commit 3d752f3
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 23 deletions.
98 changes: 77 additions & 21 deletions src/formSection/index.tsx
Expand Up @@ -2,20 +2,30 @@ import { lighten } from 'polished';
import * as React from 'react';
import styled from 'styled-components';

import Grid from '../grid';
import { EColumnSpanMode } from '../grid/column';
import { ERowAlignmentModes } from '../grid/row';
import { ITheme } from '../theme';

export enum FormSectionLabelPosition {
top,
side,
}

export interface IFormSection {
children: (inputProps: {
id: string;
'aria-describedby': string | undefined;
'aria-labelledby': string | undefined;
'aria-required': boolean | undefined;
'aria-invalid': boolean | undefined;
}) => React.ReactElement;
theme: ITheme;
title: string;
error?: string;
info?: string;
className?: string;
required?: boolean;
labelPosition?: FormSectionLabelPosition;
}

interface IFormSectionTitle {
Expand Down Expand Up @@ -67,6 +77,7 @@ const SectionInfo = styled.div<IFormSectionInfo>`
SectionInfo.displayName = 'SectionInfo';

class FormSection extends React.PureComponent<IFormSection> {
public static displayName = 'FormSection';
private static uniqueIdCounter = 0;

private uniqueId: string;
Expand All @@ -79,7 +90,17 @@ class FormSection extends React.PureComponent<IFormSection> {
}

public render() {
const { className, children, error, info, title, required } = this.props;
const { labelPosition } = this.props;

if (labelPosition === FormSectionLabelPosition.side) {
return this.renderWithLabelOnSide();
}

return this.renderWithLabelOnTop();
}

private renderWithLabelOnTop = () => {
const { children, error, info, title, required } = this.props;

// IDs for aria props
const inputId = `${this.uniqueId}__input`;
Expand All @@ -88,26 +109,61 @@ class FormSection extends React.PureComponent<IFormSection> {
const errorId = `${this.uniqueId}__error`;

return (
<div className={className}>
<SectionTitle required={required} id={labelId} htmlFor={inputId}>
{title}
</SectionTitle>
{children({
'aria-describedby': (error && errorId) || (info && infoId) || undefined,
'aria-labelledby': labelId,
id: inputId,
})}
{!error && info && <SectionInfo id={infoId}>{info}</SectionInfo>}
{error && <SectionError id={errorId}>{error}</SectionError>}
</div>
<Grid.Container fluid>
<Grid.Row noGutter>
<Grid.Column>
<SectionTitle required={required} id={labelId} htmlFor={inputId}>
{title}
</SectionTitle>
</Grid.Column>
</Grid.Row>
<Grid.Row noGutter>
<Grid.Column>
{children({
'aria-describedby': (error && errorId) || (info && infoId) || undefined,
'aria-invalid': !!error || undefined,
'aria-labelledby': labelId,
'aria-required': required,
id: inputId,
})}
{!error && info && <SectionInfo id={infoId}>{info}</SectionInfo>}
{error && <SectionError id={errorId}>{error}</SectionError>}
</Grid.Column>
</Grid.Row>
</Grid.Container>
);
}
}
};

const StyledFormSection = styled(FormSection)`
margin-bottom: 20px;
`;
private renderWithLabelOnSide = () => {
const { children, error, info, title, required } = this.props;

StyledFormSection.displayName = 'FormSection';
// IDs for aria props
const inputId = `${this.uniqueId}__input`;
const labelId = `${this.uniqueId}__label`;
const infoId = `${this.uniqueId}__info`;
const errorId = `${this.uniqueId}__error`;

return (
<Grid.Row alignmentMode={ERowAlignmentModes.baseline}>
<Grid.Column spanMode={EColumnSpanMode.fitSpace} noWrap>
<SectionTitle required={required} id={labelId} htmlFor={inputId}>
{title}
</SectionTitle>
</Grid.Column>
<Grid.Column>
{children({
'aria-describedby': (error && errorId) || (info && infoId) || undefined,
'aria-invalid': !!error || undefined,
'aria-labelledby': labelId,
'aria-required': required,
id: inputId,
})}
{!error && info && <SectionInfo id={infoId}>{info}</SectionInfo>}
{error && <SectionError id={errorId}>{error}</SectionError>}
</Grid.Column>
</Grid.Row>
);
};
}

export default StyledFormSection;
export default FormSection;
37 changes: 36 additions & 1 deletion stories/formSection.stories.tsx
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';

import { storiesOf } from '@storybook/react';

import FormSection from '../src/formSection';
import FormSection, { FormSectionLabelPosition } from '../src/formSection';
import TextInput from '../src/textInput';

import StoryColumn from './storyColumn';
Expand Down Expand Up @@ -88,4 +88,39 @@ storiesOf('Components|Molecules (Composite)/FormSection', module)
)}
</FormSection>
</StoryColumn>
))
.add('Inline Mode', () => (
<StoryColumn>
<h1>
<code>{'<FormSection />'}</code> Component
</h1>
<h2>Inline Mode</h2>
<h3>
<code>labelPosition="side"</code>
</h3>
<FormSection
labelPosition={FormSectionLabelPosition.side}
title="Brugernavn"
required
info="Alfanumeriske tegn, bindestreger og understregning kun"
>
{inputProps => (
<DemoStateWrapper
render={(text, onChange) => <TextInput value={text} onChange={onChange} {...inputProps} />}
/>
)}
</FormSection>
<FormSection
labelPosition={FormSectionLabelPosition.side}
title="Visningsnavn"
required
info="Dette vil være det navn, der vises på din profil"
>
{inputProps => (
<DemoStateWrapper
render={(text, onChange) => <TextInput value={text} onChange={onChange} {...inputProps} />}
/>
)}
</FormSection>
</StoryColumn>
));
5 changes: 4 additions & 1 deletion stories/panel.stories.tsx
Expand Up @@ -77,7 +77,10 @@ storiesOf('Components|Atoms (Basic)/Panel', module)
sveitarfélagsins Reykjavíkur er Reykjavíkurborg.
</p>
<SwitchContainer>
<DemoStateWrapper render={(on, onClick) => <Switch on={on} onClick={onClick} />} initialValue={true} />
<DemoStateWrapper
render={(on, onClick) => <Switch on={on} onText="á" offText="af" onClick={onClick} />}
initialValue={true}
/>
<div style={{ marginLeft: 20 }}>Sendu mér tölvupóst þegar þetta er í boði</div>
</SwitchContainer>
</Panel>
Expand Down

0 comments on commit 3d752f3

Please sign in to comment.