diff --git a/playwright/components/atoms/input.spec.js b/playwright/components/atoms/input.spec.js index 5d3c6831e..1c0a3bb22 100644 --- a/playwright/components/atoms/input.spec.js +++ b/playwright/components/atoms/input.spec.js @@ -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(); }); diff --git a/playwright/components/atoms/textInputWithDropdown.spec.js b/playwright/components/atoms/textInputWithDropdown.spec.js index f57f62ce2..50137be1a 100644 --- a/playwright/components/atoms/textInputWithDropdown.spec.js +++ b/playwright/components/atoms/textInputWithDropdown.spec.js @@ -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(); }); diff --git a/playwright/components/molecules/schoolLookup.spec.js b/playwright/components/molecules/schoolLookup.spec.js index 60910d7ad..c4e120ad9 100644 --- a/playwright/components/molecules/schoolLookup.spec.js +++ b/playwright/components/molecules/schoolLookup.spec.js @@ -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(); }); diff --git a/playwright/components/molecules/simpleSchoolLookUp.spec.js b/playwright/components/molecules/simpleSchoolLookUp.spec.js index 59beef212..15964d1b2 100644 --- a/playwright/components/molecules/simpleSchoolLookUp.spec.js +++ b/playwright/components/molecules/simpleSchoolLookUp.spec.js @@ -21,7 +21,7 @@ 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(''); @@ -29,7 +29,7 @@ test.describe('simple school lookup component', () => { 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(); }); }); diff --git a/playwright/components/molecules/typeahead.spec.js b/playwright/components/molecules/typeahead.spec.js index 0e063c6fa..17bcf7fa7 100644 --- a/playwright/components/molecules/typeahead.spec.js +++ b/playwright/components/molecules/typeahead.spec.js @@ -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(); }); diff --git a/playwright/components/organisms/marketingPreferences.spec.js b/playwright/components/organisms/marketingPreferences.spec.js index eaf9eca94..5fb4a37ac 100644 --- a/playwright/components/organisms/marketingPreferences.spec.js +++ b/playwright/components/organisms/marketingPreferences.spec.js @@ -41,57 +41,57 @@ test.describe('marketing preferences component', () => { await page.locator('div#marketing-preferences--default ~ input[type="submit"]').click(); // email field empty error message - await expect(page.locator('div#marketing-preferences--default div.field-email > div > label[for="mp_email"] > span > span')).toContainText('Please enter your email address'); + await expect(page.locator('div#marketing-preferences--default div.field-email > div > div > label[for="mp_email"] > span > span')).toContainText('Please enter your email address'); // postal address fields empty error messages // address line 1 error message - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_address1"] > span > span')).toContainText('Please enter the first line of your address'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_address1"] > span > span')).toContainText('Please enter the first line of your address'); // town error message - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_town"] > span > span')).toContainText('Please enter your town'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_town"] > span > span')).toContainText('Please enter your town'); // postcode error message - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter your postcode'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter your postcode'); // country error message - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_country"] > span > span')).toContainText('Please enter your country'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_country"] > span > span')).toContainText('Please enter your country'); // text empty error message - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); // phone error message - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter your phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter your phone number'); // text field empty error message - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); // phone field empty error message - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter your phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter your phone number'); // validate email field await page.locator('div#marketing-preferences--default input#mp_email').type('email-signup@email.sls.comicrelief.com'); await page.locator('div#marketing-preferences--default input#mp_email').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address1').click(); - await expect(page.locator('div#marketing-preferences--default div.field-email > div > label[for="mp_email"] > span > span')).toContainText('Please enter your email address'); + await expect(page.locator('div#marketing-preferences--default div.field-email > div > div > label[for="mp_email"] > span > span')).toContainText('Please enter your email address'); // email that has : should show error message await page.locator('div#marketing-preferences--default input#mp_email').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_email').type('test:@£$%£test@comicrelief.com'); await page.locator('div#marketing-preferences--default input#mp_address1').click(); - await expect(page.locator('div#marketing-preferences--default div.field-email > div > label[for="mp_email"] > span > span')).toContainText('Please enter a valid email address'); + await expect(page.locator('div#marketing-preferences--default div.field-email > div > div > label[for="mp_email"] > span > span')).toContainText('Please enter a valid email address'); // email that has mix of special chars that's valid and not valid should show error message await page.locator('div#marketing-preferences--default input#mp_email').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_email').type('Test0-9!#$%&\'*+/=?^_{|}~-@comicrelief_9-8.com.uk'); await page.locator('div#marketing-preferences--default input#mp_address1').click(); - await expect(page.locator('div#marketing-preferences--default div.field-email > div > label[for="mp_email"] > span > span')).toContainText('Please enter a valid email address'); + await expect(page.locator('div#marketing-preferences--default div.field-email > div > div > label[for="mp_email"] > span > span')).toContainText('Please enter a valid email address'); // postal address fields validation // validate address line 1 field await page.locator('div#marketing-preferences--default input#mp_address1').type('Comic Relief'); await page.locator('div#marketing-preferences--default input#mp_address1').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_address1"] > span > span')).toContainText('Please enter the first line of your address'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_address1"] > span > span')).toContainText('Please enter the first line of your address'); // address line 1 with special characters should show error message await page.locator('div#marketing-preferences--default input#mp_address1').type('Comic @% Relief'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_address1"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_address1"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); // address line 1 with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_address1').fill('Comic Relief'); // clear the email field @@ -111,108 +111,108 @@ test.describe('marketing preferences component', () => { await page.locator('div#marketing-preferences--default input#mp_town').type('London'); await page.locator('div#marketing-preferences--default input#mp_town').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_town"] > span > span')).toContainText('Please enter your town'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_town"] > span > span')).toContainText('Please enter your town'); // town field with special characters should show error message await page.locator('div#marketing-preferences--default input#mp_town').type('Lon@%don '); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_town"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_town"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); // town field with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_town').fill('LONDON'); // clear the email field - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_town"] > span > span')).toBeHidden(''); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_town"] > span > span')).toBeHidden(''); // postcode field should show error message when value is not entered await page.locator('div#marketing-preferences--default input#mp_postcode').type('E1 8QS'); await page.locator('div#marketing-preferences--default input#mp_postcode').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter your postcode'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter your postcode'); // postcode field with a space should show error message await page.locator('div#marketing-preferences--default input#mp_postcode').type('E 1 8QS'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter a valid postcode'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter a valid postcode'); // postcode field with a space in second part should show error message await page.locator('div#marketing-preferences--default input#mp_postcode').type('E1 8 QS'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter a valid postcode'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_postcode"] > span > span')).toContainText('Please enter a valid postcode'); // postcode field with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_postcode').fill('E1 8QS'); // clear the email field - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_postcode"] > span > span')).toBeHidden(''); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_postcode"] > span > span')).toBeHidden(''); // country field should show error message when value is not entered await page.locator('div#marketing-preferences--default input#mp_country').type('United Kingdom'); await page.locator('div#marketing-preferences--default input#mp_country').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_country"] > span > span')).toContainText('Please enter your country'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_country"] > span > span')).toContainText('Please enter your country'); // country field with special characters should show error message await page.locator('div#marketing-preferences--default input#mp_country').type('United £$^3 Kingdom'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_country"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_country"] > span > span')).toContainText('This field only accepts alphanumeric characters and , . ( ) / & \' - and must start with an alphanumeric character'); // country field with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_country').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_country').fill('United Kingdom'); // clear the email field - await expect(page.locator('div#marketing-preferences--default div.field-post > div > label[for="mp_country"] > span > span')).toBeHidden(''); + await expect(page.locator('div#marketing-preferences--default div.field-post > div > div > label[for="mp_country"] > span > span')).toBeHidden(''); // sms field should show error message when value is not entered await page.locator('div#marketing-preferences--default input#mp_mobile').type('07123456789'); await page.locator('div#marketing-preferences--default input#mp_mobile').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter your mobile number'); // sms field with 10 digits should show error message await page.locator('div#marketing-preferences--default input#mp_mobile').type('0712345678'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); // sms field with 12 digits should show error message await page.locator('div#marketing-preferences--default input#mp_mobile').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_mobile').type('071234567890'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); // sms field starting with a space should show error message await page.locator('div#marketing-preferences--default input#mp_mobile').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_mobile').type(' 07123456789'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toContainText('Please enter a valid UK mobile number'); // sms field with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_mobile').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_mobile').fill('07123456789'); - await expect(page.locator('div#marketing-preferences--default div.field-sms > div > label[for="mp_mobile"] > span > span')).toBeHidden(''); + await expect(page.locator('div#marketing-preferences--default div.field-sms > div > div > label[for="mp_mobile"] > span > span')).toBeHidden(''); // phone field should show error message when value is not entered await page.locator('div#marketing-preferences--default input#mp_phone').type('02081234567'); await page.locator('div#marketing-preferences--default input#mp_phone').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter your phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter your phone number'); // phone field with 10 digits should show error message await page.locator('div#marketing-preferences--default input#mp_phone').type('0208123456'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter a valid UK phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter a valid UK phone number'); // phone field with 12 digits should show error message await page.locator('div#marketing-preferences--default input#mp_phone').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_phone').type('020812345678'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter a valid UK phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter a valid UK phone number'); // phone field starting with a space should show error message await page.locator('div#marketing-preferences--default input#mp_phone').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_phone').type(' 02081234567'); await page.locator('div#marketing-preferences--default input#mp_address2').click(); - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toContainText('Please enter a valid UK phone number'); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toContainText('Please enter a valid UK phone number'); // phone field with valid input should not show error message await page.locator('div#marketing-preferences--default input#mp_phone').fill(''); // clear the email field await page.locator('div#marketing-preferences--default input#mp_phone').fill('02081234567'); - await expect(page.locator('div#marketing-preferences--default div.field-phone > div > label > span > span')).toBeHidden(''); + await expect(page.locator('div#marketing-preferences--default div.field-phone > div > div > label > span > span')).toBeHidden(''); await page.close(); }); diff --git a/src/components/Atoms/Input/Input.js b/src/components/Atoms/Input/Input.js index 7e0036f61..755503cb2 100644 --- a/src/components/Atoms/Input/Input.js +++ b/src/components/Atoms/Input/Input.js @@ -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( ( @@ -99,43 +30,45 @@ const Input = React.forwardRef( }, ref ) => ( - + + + ) ); diff --git a/src/components/Atoms/Input/Input.md b/src/components/Atoms/Input/Input.md index 259588379..2348f0053 100644 --- a/src/components/Atoms/Input/Input.md +++ b/src/components/Atoms/Input/Input.md @@ -7,6 +7,7 @@ label="Label" id="input-example-1" showLabel={true} + optional /> ``` diff --git a/src/components/Atoms/Input/Input.style.js b/src/components/Atoms/Input/Input.style.js new file mode 100644 index 000000000..d0220295a --- /dev/null +++ b/src/components/Atoms/Input/Input.style.js @@ -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 +}; diff --git a/src/components/Atoms/Input/input.test.js b/src/components/Atoms/Input/input.test.js index 2e949cdc0..2b6043b9f 100644 --- a/src/components/Atoms/Input/input.test.js +++ b/src/components/Atoms/Input/input.test.js @@ -16,7 +16,7 @@ it('renders correctly', () => { ).toJSON(); expect(tree).toMatchInlineSnapshot(` - .c1 { + .c2 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -24,7 +24,7 @@ it('renders correctly', () => { font-family: 'Montserrat',Helvetica,Arial,sans-serif; } - .c0 { + .c1 { width: 100%; position: relative; display: -webkit-box; @@ -37,17 +37,21 @@ it('renders correctly', () => { color: #5C5C5E; } - .c2 { + .c3 { margin-bottom: 0.5rem; font-weight: normal; } - .c3 { + .c0 { + width: 100%; + } + + .c4 { position: relative; font-size: 1.25rem; } - .c4 { + .c5 { position: relative; width: 100%; display: -webkit-box; @@ -64,7 +68,7 @@ it('renders correctly', () => { align-items: center; } - .c5 { + .c6 { position: relative; box-sizing: border-box; width: 100%; @@ -84,56 +88,54 @@ it('renders correctly', () => { font-family: 'Montserrat',Helvetica,Arial,sans-serif; } - .c5:focus { + .c6:focus { border: 1px solid #666; } @media (min-width:740px) { - .c4 { - max-width: 290px; - } - } - - @media (min-width:740px) { - .c5 { + .c0 { max-width: 290px; } } - + + + `); }); diff --git a/src/components/Atoms/TextInputWithDropdown/__snapshots__/TextInputWithDropdown.test.js.snap b/src/components/Atoms/TextInputWithDropdown/__snapshots__/TextInputWithDropdown.test.js.snap index 79ca19efa..4a1f28a73 100644 --- a/src/components/Atoms/TextInputWithDropdown/__snapshots__/TextInputWithDropdown.test.js.snap +++ b/src/components/Atoms/TextInputWithDropdown/__snapshots__/TextInputWithDropdown.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly with no value and no options 1`] = ` -.c2 { +.c3 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -9,7 +9,7 @@ exports[`renders correctly with no value and no options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c1 { +.c2 { width: 100%; position: relative; display: -webkit-box; @@ -22,17 +22,21 @@ exports[`renders correctly with no value and no options 1`] = ` color: #5C5C5E; } -.c3 { +.c4 { margin-bottom: 0.5rem; font-weight: normal; } -.c4 { +.c1 { + width: 100%; +} + +.c5 { position: relative; font-size: 1.25rem; } -.c5 { +.c6 { position: relative; width: 100%; display: -webkit-box; @@ -49,7 +53,7 @@ exports[`renders correctly with no value and no options 1`] = ` align-items: center; } -.c6 { +.c7 { position: relative; box-sizing: border-box; width: 100%; @@ -69,7 +73,7 @@ exports[`renders correctly with no value and no options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c6:focus { +.c7:focus { border: 1px solid #666; } @@ -78,13 +82,7 @@ exports[`renders correctly with no value and no options 1`] = ` } @media (min-width:740px) { - .c5 { - max-width: 290px; - } -} - -@media (min-width:740px) { - .c6 { + .c1 { max-width: 290px; } } @@ -93,49 +91,53 @@ exports[`renders correctly with no value and no options 1`] = ` className="c0 TextInputWithDropdown" onKeyDown={[Function]} > - + + + `; exports[`renders correctly with value and no options 1`] = ` -.c2 { +.c3 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -143,7 +145,7 @@ exports[`renders correctly with value and no options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c1 { +.c2 { width: 100%; position: relative; display: -webkit-box; @@ -156,17 +158,21 @@ exports[`renders correctly with value and no options 1`] = ` color: #5C5C5E; } -.c3 { +.c4 { margin-bottom: 0.5rem; font-weight: normal; } -.c4 { +.c1 { + width: 100%; +} + +.c5 { position: relative; font-size: 1.25rem; } -.c5 { +.c6 { position: relative; width: 100%; display: -webkit-box; @@ -183,7 +189,7 @@ exports[`renders correctly with value and no options 1`] = ` align-items: center; } -.c6 { +.c7 { position: relative; box-sizing: border-box; width: 100%; @@ -203,7 +209,7 @@ exports[`renders correctly with value and no options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c6:focus { +.c7:focus { border: 1px solid #666; } @@ -212,13 +218,7 @@ exports[`renders correctly with value and no options 1`] = ` } @media (min-width:740px) { - .c5 { - max-width: 290px; - } -} - -@media (min-width:740px) { - .c6 { + .c1 { max-width: 290px; } } @@ -227,49 +227,53 @@ exports[`renders correctly with value and no options 1`] = ` className="c0 TextInputWithDropdown" onKeyDown={[Function]} > - + + + `; exports[`renders correctly with value and options 1`] = ` -.c2 { +.c3 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -277,7 +281,7 @@ exports[`renders correctly with value and options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c1 { +.c2 { width: 100%; position: relative; display: -webkit-box; @@ -290,17 +294,21 @@ exports[`renders correctly with value and options 1`] = ` color: #5C5C5E; } -.c3 { +.c4 { margin-bottom: 0.5rem; font-weight: normal; } -.c4 { +.c1 { + width: 100%; +} + +.c5 { position: relative; font-size: 1.25rem; } -.c5 { +.c6 { position: relative; width: 100%; display: -webkit-box; @@ -317,7 +325,7 @@ exports[`renders correctly with value and options 1`] = ` align-items: center; } -.c6 { +.c7 { position: relative; box-sizing: border-box; width: 100%; @@ -337,7 +345,7 @@ exports[`renders correctly with value and options 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c6:focus { +.c7:focus { border: 1px solid #666; } @@ -345,7 +353,7 @@ exports[`renders correctly with value and options 1`] = ` position: relative; } -.c7 { +.c8 { z-index: 3; font-family: 'Montserrat',Helvetica,Arial,sans-serif; position: absolute; @@ -358,40 +366,34 @@ exports[`renders correctly with value and options 1`] = ` width: 100%; } -.c8 { +.c9 { list-style: none; padding: 0; margin: 0; } -.c9 { +.c10 { padding: 0.5rem; } -.c10 { +.c11 { cursor: pointer; border-top: 1px solid #F4F3F5; } -.c10:hover, -.c10:focus { +.c11:hover, +.c11:focus { background-color: #F4F3F5; } @media (min-width:740px) { - .c5 { - max-width: 290px; - } -} - -@media (min-width:740px) { - .c6 { + .c1 { max-width: 290px; } } @media (min-width:740px) { - .c7 { + .c8 { max-width: 500px; } } @@ -400,55 +402,59 @@ exports[`renders correctly with value and options 1`] = ` className="c0 TextInputWithDropdown" onKeyDown={[Function]} > - + + +
`; diff --git a/src/components/Molecules/SearchInput/SearchInput.test.js b/src/components/Molecules/SearchInput/SearchInput.test.js index 423cdbcd4..826a79606 100644 --- a/src/components/Molecules/SearchInput/SearchInput.test.js +++ b/src/components/Molecules/SearchInput/SearchInput.test.js @@ -15,7 +15,7 @@ it('renders correctly', () => { ).toJSON(); expect(tree).toMatchInlineSnapshot(` - .c6 { + .c7 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -23,7 +23,7 @@ it('renders correctly', () => { font-family: 'Montserrat',Helvetica,Arial,sans-serif; } - .c4 { + .c5 { width: 100%; position: relative; display: -webkit-box; @@ -36,7 +36,7 @@ it('renders correctly', () => { color: #5C5C5E; } - .c7 { + .c8 { border: 0; -webkit-clip: rect(0 0 0 0); clip: rect(0 0 0 0); @@ -51,12 +51,16 @@ it('renders correctly', () => { width: 1px; } - .c8 { + .c4 { + width: 100%; + } + + .c9 { position: relative; font-size: 1.25rem; } - .c9 { + .c10 { position: relative; width: 100%; display: -webkit-box; @@ -73,7 +77,7 @@ it('renders correctly', () => { align-items: center; } - .c10 { + .c11 { position: relative; box-sizing: border-box; width: 100%; @@ -93,7 +97,7 @@ it('renders correctly', () => { font-family: 'Montserrat',Helvetica,Arial,sans-serif; } - .c10:focus { + .c11:focus { border: 1px solid #666; } @@ -120,7 +124,7 @@ it('renders correctly', () => { padding: 0 0.5rem; } - .c5 input { + .c6 input { padding: 13px 0; margin: 0; max-width: 100%; @@ -129,24 +133,18 @@ it('renders correctly', () => { background: none; } - .c5 input:focus { + .c6 input:focus { border: 0; } @media (min-width:740px) { - .c9 { - max-width: 290px; - } - } - - @media (min-width:740px) { - .c10 { + .c4 { max-width: 290px; } } @media (min-width:740px) { - .c5 input { + .c6 input { height: 100px; font-size: 3rem; } @@ -165,44 +163,48 @@ it('renders correctly', () => {
- + + +
diff --git a/src/components/Molecules/Typeahead/__snapshots__/Typeahead.test.js.snap b/src/components/Molecules/Typeahead/__snapshots__/Typeahead.test.js.snap index 30c065ff5..6836b9479 100644 --- a/src/components/Molecules/Typeahead/__snapshots__/Typeahead.test.js.snap +++ b/src/components/Molecules/Typeahead/__snapshots__/Typeahead.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly 1`] = ` -.c2 { +.c3 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -9,7 +9,7 @@ exports[`renders correctly 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c1 { +.c2 { width: 100%; position: relative; display: -webkit-box; @@ -22,17 +22,21 @@ exports[`renders correctly 1`] = ` color: #5C5C5E; } -.c3 { +.c4 { margin-bottom: 0.5rem; font-weight: normal; } -.c4 { +.c1 { + width: 100%; +} + +.c5 { position: relative; font-size: 1.25rem; } -.c5 { +.c6 { position: relative; width: 100%; display: -webkit-box; @@ -49,7 +53,7 @@ exports[`renders correctly 1`] = ` align-items: center; } -.c6 { +.c7 { position: relative; box-sizing: border-box; width: 100%; @@ -69,7 +73,7 @@ exports[`renders correctly 1`] = ` font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c6:focus { +.c7:focus { border: 1px solid #666; } @@ -78,13 +82,7 @@ exports[`renders correctly 1`] = ` } @media (min-width:740px) { - .c5 { - max-width: 290px; - } -} - -@media (min-width:740px) { - .c6 { + .c1 { max-width: 290px; } } @@ -93,43 +91,47 @@ exports[`renders correctly 1`] = ` className="c0 TextInputWithDropdown" onKeyDown={[Function]} > - + + + `; diff --git a/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap b/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap index 274ae62ef..0f270254f 100644 --- a/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap +++ b/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap @@ -33,7 +33,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c20 { +.c21 { font-size: 1rem; line-height: 1rem; text-transform: inherit; @@ -41,7 +41,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c18 { +.c19 { width: 100%; position: relative; display: -webkit-box; @@ -54,17 +54,21 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend color: #5C5C5E; } -.c21 { +.c22 { margin-bottom: 0.5rem; font-weight: normal; } -.c22 { +.c18 { + width: 100%; +} + +.c23 { position: relative; font-size: 1.25rem; } -.c23 { +.c24 { position: relative; width: 100%; display: -webkit-box; @@ -81,7 +85,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend align-items: center; } -.c24 { +.c25 { position: relative; box-sizing: border-box; width: 100%; @@ -101,7 +105,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend font-family: 'Montserrat',Helvetica,Arial,sans-serif; } -.c24:focus { +.c25:focus { border: 1px solid #666; } @@ -213,7 +217,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend justify-content: center; } -.c19 { +.c20 { position: relative; -webkit-flex-basis: 50%; -ms-flex-preferred-size: 50%; @@ -229,7 +233,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend display: block; } -.c19 span { +.c20 span { position: absolute; font-size: 20px; top: 50%; @@ -242,7 +246,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend z-index: 3; } -.c19 input { +.c20 input { height: 48px; border: 2px solid #969598; background: #F4F3F5; @@ -250,17 +254,17 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend padding: 0.5rem 1rem 0.5rem 2rem; } -.c19 input:focus { +.c20 input:focus { outline: none; border: 2px solid #969598; } -.c25 { +.c26 { line-height: 1.5; margin-top: 2rem; } -.c26 { +.c27 { width: 100%; margin: 2rem 0 2rem; color: #FFFFFF; @@ -279,9 +283,9 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend appearance: none; } -.c26:active, -.c26:focus, -.c26:hover { +.c27:active, +.c27:focus, +.c27:hover { outline: none; background-color: #961D35; } @@ -432,13 +436,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend } @media (min-width:740px) { - .c23 { - max-width: 290px; - } -} - -@media (min-width:740px) { - .c24 { + .c18 { max-width: 290px; } } @@ -512,7 +510,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend } @media (min-width:740px) { - .c19 { + .c20 { -webkit-flex-basis: 60%; -ms-flex-preferred-size: 60%; flex-basis: 60%; @@ -520,7 +518,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend } @media (min-width:740px) { - .c26 { + .c27 { padding: 1rem 2rem; } } @@ -630,51 +628,55 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend
- + + +

£345.67 @@ -682,7 +684,7 @@ exports[`"Single Giving, No Money Buys, with overridden manual input value" rend will help us fund amazing projects in the UK and around the world.