Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion playwright/components/atoms/input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ test.describe('input component', () => {
await page.locator('#input-example-2').type('This is test input text');

// error message should be visible
await expect(page.locator('[data-preview="Input"] > div > label > span[data-test="error-message"]')).toBeVisible();
await expect(page.locator('[data-preview="Input"] > div > div > label > span[data-test="error-message"]')).toBeVisible();

await page.close();
});
Expand Down
4 changes: 2 additions & 2 deletions playwright/components/atoms/textInputWithDropdown.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ test.describe('Text Input With Dropdown Component', () => {
await page.locator('label[for="input-with-dropdown"]').type('test');

// ensure select dropdown values are visible
await expect(page.locator('label[for="input-with-dropdown"] ~ div > ul[role="listbox"]')).toBeVisible();
await expect(page.locator('ul[role="listbox"]')).toBeVisible();

await page.locator('label[for="input-with-dropdown"] ~ div > ul[role="listbox"] > li[id="option-1"]').click();
await page.locator('ul[role="listbox"] > li[id="option-1"]').click();

await page.close();
});
Expand Down
4 changes: 2 additions & 2 deletions playwright/components/molecules/schoolLookup.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ test.describe('school lookup component', () => {
expect(placeholderAttribute).toBe('Type to start search');

await page.locator('#school-lookup').type('St Paul');
await expect(page.locator('label[for="school-lookup"] ~ div > ul[role="listbox"]')).toBeVisible();
await page.locator('label[for="school-lookup"] ~ div > ul[role="listbox"] > li[id="option-6"]').click();
await expect(page.locator('ul[role="listbox"]')).toBeVisible();
await page.locator('ul[role="listbox"] > li[id="option-6"]').click();

await page.close();
});
Expand Down
4 changes: 2 additions & 2 deletions playwright/components/molecules/simpleSchoolLookUp.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ test.describe('simple school lookup component', () => {
await page.locator('input#school_lookup').type('St Paul');
await expect(page.locator('[data-preview="SimpleSchoolLookup"] > div > div > button[type="button"]')).toBeVisible();
await page.locator('[data-preview="SimpleSchoolLookup"] > div > div > button[type="button"]').click();
await expect(page.locator('label[for="school_lookup"] ~ div > ul[role="listbox"]')).toBeVisible();
await expect(page.locator('ul[role="listbox"]')).toBeVisible();

// clear school name and enter school postcode
await page.locator('input#school_lookup').fill('');
await page.locator('input#school_lookup').fill('EC4M 9AD');
await expect(page.locator('[data-preview="SimpleSchoolLookup"] > div > div > button[type="button"]')).toBeVisible();
await page.locator('[data-preview="SimpleSchoolLookup"] > div > div > button[type="button"]').click();

await expect(page.locator('label[for="school_lookup"] ~ div > ul[role="listbox"]')).toBeVisible();
await expect(page.locator('ul[role="listbox"]')).toBeVisible();
await page.close();
});
});
4 changes: 2 additions & 2 deletions playwright/components/molecules/typeahead.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ test.describe('typeahead component', () => {

// type a word and typeahead should give options
await page.locator('input#typeahead-test').type('red nos');
await expect(page.locator('label[for="typeahead-test"] ~ div > ul[role="listbox"]')).toBeVisible();
await expect(page.locator('label[for="typeahead-test"] ~ div > ul[role="listbox"] > li[id="option-0"]')).toContainText('red nose');
await expect(page.locator('ul[role="listbox"]')).toBeVisible();
await expect(page.locator('ul[role="listbox"] > li[id="option-0"]')).toContainText('red nose');

await page.close();
});
Expand Down
68 changes: 34 additions & 34 deletions playwright/components/organisms/marketingPreferences.spec.js

Large diffs are not rendered by default.

161 changes: 47 additions & 114 deletions src/components/Atoms/Input/Input.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';

import alertIcon from './assets/error-alert-icon-red.svg';
import Label from '../Label/Label';
import ErrorText from '../ErrorText/ErrorText';
import zIndex from '../../../theme/shared/zIndex';

// This seems to get a decent approximation of the necessary width (without resorting to measuring
// the element with JS)
const getPrefixWidth = prefixLength => `calc(1.5rem + (${prefixLength} * 0.5rem))`;

const InputWrapper = styled.div`
position: relative;
font-size: ${({ theme }) => theme.fontSize('m')};
`;

const InputFieldContainer = styled.div`
position: relative;
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;

@media ${({ theme }) => theme.allBreakpoints('M')} {
max-width: 290px;
}
`;

const InputField = styled.input`${({ theme, error, prefixLength }) => css`
position: relative;
box-sizing: border-box;
width: 100%;
height: 48px;
padding: 1rem 2.4rem 1rem 1.5rem;
${prefixLength > 0 ? `padding-left: ${getPrefixWidth(prefixLength)};` : ''}
background-color: ${theme.color('grey_light')};
border: 1px solid;
border-color: ${error ? theme.color('red') : theme.color('grey_medium')};
box-shadow: none;
appearance: none;
color: ${theme.color('black')};
border-radius: 0.5rem;
font-size: inherit;
z-index: 2;
font-family: ${theme.fontFamilies(theme.font.regular)};

:focus {
border: 1px solid ${theme.color('grey_for_forms')};
}

@media ${theme.allBreakpoints('M')} {
max-width: 290px;
}
`}`;

const ErrorIconWrapper = styled.div`
position: absolute;
right: 0.6rem;
background: url(${alertIcon}) center/contain no-repeat;
--iconSize: 19px;
width: var(--iconSize);
height: var(--iconSize);
z-index: 3;
`;

const Prefix = styled.div`
position: absolute;
left: 0;
top: 0;
${zIndex('high')}
display: flex;
height: 100%;
width: ${({ length }) => getPrefixWidth(length)};
justify-content: center;
align-items: center;
color: ${({ theme }) => theme.color('grey_dark')};
font-weight: 700;
font-size: inherit;
margin-left: 2px; // Just doesn't look quite right without this.
`;
import {
Container,
InputWrapper,
InputFieldContainer,
InputField,
ErrorIconWrapper,
Prefix
} from './Input.style';

const Input = React.forwardRef(
(
Expand All @@ -99,43 +30,45 @@ const Input = React.forwardRef(
},
ref
) => (
<Label
className={className}
htmlFor={id}
label={label}
hideLabel={!showLabel}
errorMsg={errorMsg}
optional={optional}
{...labelProps}
>
<InputWrapper error={Boolean(errorMsg)}>
{prefix && <Prefix length={prefix.length}>{prefix}</Prefix>}
<InputFieldContainer>
<InputField
id={id}
type={type}
placeholder={placeholder}
error={Boolean(errorMsg)}
aria-describedby={hasAria ? id : undefined}
ref={ref}
prefixLength={prefix.length}
required={optional === false}
{...rest}
/>
{errorMsg && <ErrorIconWrapper />}
</InputFieldContainer>
</InputWrapper>
{errorMsg
&& (
<ErrorText
size="sm"
weight="bold"
data-test="error-message"
>
{errorMsg}
</ErrorText>
)}
</Label>
<Container>
<Label
className={className}
htmlFor={id}
label={label}
hideLabel={!showLabel}
errorMsg={errorMsg}
optional={optional}
{...labelProps}
>
<InputWrapper error={Boolean(errorMsg)}>
{prefix && <Prefix length={prefix.length}>{prefix}</Prefix>}
<InputFieldContainer>
<InputField
id={id}
type={type}
placeholder={placeholder}
error={Boolean(errorMsg)}
aria-describedby={hasAria ? id : undefined}
ref={ref}
prefixLength={prefix.length}
required={optional === false}
{...rest}
/>
{errorMsg && <ErrorIconWrapper />}
</InputFieldContainer>
</InputWrapper>
{errorMsg
&& (
<ErrorText
size="sm"
weight="bold"
data-test="error-message"
>
{errorMsg}
</ErrorText>
)}
</Label>
</Container>
)
);

Expand Down
1 change: 1 addition & 0 deletions src/components/Atoms/Input/Input.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
label="Label"
id="input-example-1"
showLabel={true}
optional
/>
```

Expand Down
86 changes: 86 additions & 0 deletions src/components/Atoms/Input/Input.style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import styled, { css } from 'styled-components';
import alertIcon from './assets/error-alert-icon-red.svg';
import zIndex from '../../../theme/shared/zIndex';

// This seems to get a decent approximation of the necessary width (without resorting to measuring
// the element with JS)

const getPrefixWidth = prefixLength => `calc(1.5rem + (${prefixLength} * 0.5rem))`;

const Container = styled.div`
width: 100%;
@media ${({ theme }) => theme.allBreakpoints('M')} {
max-width: 290px;
}
`;

const InputWrapper = styled.div`
position: relative;
font-size: ${({ theme }) => theme.fontSize('m')};
`;

const InputFieldContainer = styled.div`
position: relative;
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
`;

const InputField = styled.input`${({ theme, error, prefixLength }) => css`
position: relative;
box-sizing: border-box;
width: 100%;
height: 48px;
padding: 1rem 2.4rem 1rem 1.5rem;
${prefixLength > 0 ? `padding-left: ${getPrefixWidth(prefixLength)};` : ''}
background-color: ${theme.color('grey_light')};
border: 1px solid;
border-color: ${error ? theme.color('red') : theme.color('grey_medium')};
box-shadow: none;
appearance: none;
color: ${theme.color('black')};
border-radius: 0.5rem;
font-size: inherit;
z-index: 2;
font-family: ${theme.fontFamilies(theme.font.regular)};

:focus {
border: 1px solid ${theme.color('grey_for_forms')};
}
`}`;

const ErrorIconWrapper = styled.div`
position: absolute;
right: 0.6rem;
background: url(${alertIcon}) center/contain no-repeat;
--iconSize: 19px;
width: var(--iconSize);
height: var(--iconSize);
z-index: 3;
`;

const Prefix = styled.div`
position: absolute;
left: 0;
top: 0;
${zIndex('high')}
display: flex;
height: 100%;
width: ${({ length }) => getPrefixWidth(length)};
justify-content: center;
align-items: center;
color: ${({ theme }) => theme.color('grey_dark')};
font-weight: 700;
font-size: inherit;
margin-left: 2px; // Just doesn't look quite right without this.
`;

export {
Container,
InputWrapper,
InputFieldContainer,
InputField,
ErrorIconWrapper,
Prefix
};
Loading