diff --git a/src/_style.scss b/src/_style.scss index a3a6b70c..92d88382 100644 --- a/src/_style.scss +++ b/src/_style.scss @@ -14,6 +14,22 @@ $microsoft-focus-black: #000; $apple-black: #000000; $apple-focus-black: $apple-black; +.sr-only { + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; +} + +.focus-out { + position: absolute; + padding-left: 17px; + opacity: 0.75; + z-index: 1; +} + .alert-link { font-weight: normal; text-decoration: underline; @@ -219,21 +235,21 @@ $apple-focus-black: $apple-black; padding-left: 14px; } -.opt-inline-field{ - display: inline-block; - width: 50%; +.opt-inline-field { + display: inline-block; + width: 50%; } -.opt-year-field{ - padding-left: 15px; +.opt-year-field { + padding-left: 15px; } .invalid-feedback { color: $red; } -.full-vertical-height{ - height: 100vh; +.full-vertical-height { + height: 100vh; } .help-links { @@ -257,7 +273,7 @@ $apple-focus-black: $apple-black; } .mt-10 { - margin-top: 10px; + margin-top: 10px; } .pt-10 { @@ -281,7 +297,7 @@ $apple-focus-black: $apple-black; .section-heading-line { position: relative; text-align: center; - + &:before, &:after { width: 10%; diff --git a/src/common-components/AuthnValidationFormGroup.jsx b/src/common-components/AuthnValidationFormGroup.jsx index 8084eba8..a17b98d4 100644 --- a/src/common-components/AuthnValidationFormGroup.jsx +++ b/src/common-components/AuthnValidationFormGroup.jsx @@ -1,6 +1,5 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; -import { injectIntl } from '@edx/frontend-platform/i18n'; import { Form, Input, @@ -11,13 +10,11 @@ const AuthnCustomValidationFormGroup = (props) => { const { onClick, onChange, onBlur } = props; const [showHelpText, setShowHelpText] = useState(false); const [showLabelText, setShowLabelText] = useState(false); - const [showPlaceholder, setShowPlaceHolder] = useState(true); // handler code that need to be invoked via input const onClickHandler = (e, clickCb) => { setShowHelpText(true); setShowLabelText(true); - setShowPlaceHolder(false); if (clickCb) { clickCb(e); } @@ -25,7 +22,6 @@ const AuthnCustomValidationFormGroup = (props) => { const onBlurHandler = (e, blurCb) => { setShowHelpText(false); setShowLabelText(false); - setShowPlaceHolder(true); if (blurCb) { blurCb(e); } @@ -38,12 +34,18 @@ const AuthnCustomValidationFormGroup = (props) => { const onOptionalHandler = (e, clickCb) => { clickCb(e); }; const showLabel = () => { - const fieldLabel = (!props.optionalFieldCheckbox && showLabelText) ? ( - - {props.label} - - ) : ; - return fieldLabel; + let className; + if (props.optionalFieldCheckbox || (!showLabelText && (props.value !== '' || props.type === 'select'))) { + className = 'sr-only'; + } else if (showLabelText) { + className = 'pt-10 h6'; + } else { + className = 'pt-10 focus-out'; + } + + return ( + {props.label} + ); }; const showOptional = () => { const additionalField = props.optionalFieldCheckbox ? ( @@ -60,7 +62,6 @@ const AuthnCustomValidationFormGroup = (props) => { type: props.type, value: props.value, }; - inputProps.placeholder = showPlaceholder ? props.label : ''; inputProps.onChange = (e) => onChangeHandler(e, onChange); inputProps.onClick = (e) => onClickHandler(e, onClick); inputProps.onBlur = (e) => onBlurHandler(e, onBlur); @@ -145,4 +146,4 @@ AuthnCustomValidationFormGroup.propTypes = { })), }; -export default injectIntl(AuthnCustomValidationFormGroup); +export default AuthnCustomValidationFormGroup; diff --git a/src/common-components/tests/AuthnValidationFormGroup.test.jsx b/src/common-components/tests/AuthnValidationFormGroup.test.jsx new file mode 100644 index 00000000..88f3dfbf --- /dev/null +++ b/src/common-components/tests/AuthnValidationFormGroup.test.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import AuthnCustomValidationFormGroup from '../AuthnValidationFormGroup'; + +describe('AuthnCustomValidationFormGroup', () => { + let props = { + label: 'Email Label', + for: 'email', + name: 'email', + type: 'email', + value: '', + helpText: 'Email field help text', + }; + + it('should show label in place of placeholder when field is empty', () => { + const validationFormGroup = mount(); + expect(validationFormGroup.find('label').prop('className')).toEqual('pt-10 focus-out form-label'); + }); + + it('should show label on top of field when field is focused in', () => { + const validationFormGroup = mount(); + + validationFormGroup.find('input').simulate('focus'); + expect(validationFormGroup.find('label').prop('className')).toEqual('pt-10 h6 form-label'); + }); + + it('should keep label hidden for checkbox field', () => { + props = { + ...props, + type: 'checkbox', + optionalFieldCheckbox: true, + }; + const validationFormGroup = mount(); + expect(validationFormGroup.find('label').prop('className')).toEqual('sr-only form-label'); + }); + + it('should keep label hidden when input field is not empty', () => { + props = { + ...props, + value: 'test', + }; + const validationFormGroup = mount(); + expect(validationFormGroup.find('label').prop('className')).toEqual('sr-only form-label'); + }); +}); diff --git a/src/forgot-password/tests/__snapshots__/ForgotPasswordPage.test.jsx.snap b/src/forgot-password/tests/__snapshots__/ForgotPasswordPage.test.jsx.snap index 4f05be99..5a886582 100644 --- a/src/forgot-password/tests/__snapshots__/ForgotPasswordPage.test.jsx.snap +++ b/src/forgot-password/tests/__snapshots__/ForgotPasswordPage.test.jsx.snap @@ -23,7 +23,12 @@ exports[`ForgotPasswordPage should match default section snapshot 1`] = `
- + - + - + - + - + - + - + - + - + - + - + - + - + {getConfig().REGISTRATION_OPTIONAL_FIELDS ? ( { expect(registrationPage.find('#validation-errors').first().text()).toEqual(alertBanner); }); - it('should show error message on alert and below the fields incase of 409', () => { + it('should show error message on alert and below the fields in case of 409', () => { const errors = { email: 'It looks like test@gmail.com belongs to an existing account. Try again with a different email address.', username: 'It looks like test belongs to an existing account. Try again with a different username.', @@ -338,7 +338,7 @@ describe('RegistrationPageTests', () => { expect(store.dispatch).toHaveBeenCalledWith(registerNewUser(formPayload)); }); - it('should display validationAlertMessages incase of invalid form submission', () => { + it('should display validationAlertMessages in case of invalid form submission', () => { const alertMessages = { name: [{ user_message: 'Please enter your full name.' }], username: [{ user_message: 'Please enter your public username.' }], diff --git a/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap b/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap index 68fe577d..64f5e49e 100644 --- a/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap +++ b/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap @@ -35,7 +35,12 @@ exports[`RegistrationPageTests should match TPA provider snapshot 1`] = `
- + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +