diff --git a/README.md b/README.md index 8ad77ef..17e90a8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ npm install --save react-eureka ```jsx import React, { Component } from 'react'; -import { EurekaForm } from 'react-eureka'; +import { EurekaForm, Question } from 'react-eureka'; class EurekaDemo extends Component { constructor(props) { @@ -27,7 +27,7 @@ class EurekaDemo extends Component { formSubmitted: false }; } - + _onSubmit = () => this.setState({...this.state, formSubmitted: true}) render() { @@ -43,13 +43,13 @@ class EurekaDemo extends Component { What's your name - + Hello {values.name}, and your email? - + - + Phone Number? - + } @@ -84,7 +84,7 @@ there are 2 APIs you can use (you can actually use both, but we don't recomend i in the questions API you pass your questions as a JSON object. in the React children API you pass the components you want to display as your questions. -## questions API +## questions array API ```js const questions = [{ @@ -102,22 +102,63 @@ const questions = [{ ``` -## React children API -*Note:* **The type prop sets both the HTML form type and the key in the values object** +## React Component API +*Note:* **The type prop sets both the HTML form type and the key in the +values object** +each child you give to EurekaForm will be treated as a `question`, the +easiest way is to use the `Question` helper we provide. + +### Question Helper ```jsx - + What's your name - - + + Hello {values.name}, and your email? - - + + Phone Number? - + ``` +### Full API +In order to implement your own Question Helper you just need to call +`onChange` when your value changes, if you are going to use an `` +tag, please pass down the `type` property to make sure HTML5 validation +still works. You should also make sure to gracefully handle the `children` +prop, as it'll be usual to pass down the question component there. + +```jsx +const InputQuestion = ({ onChange, type, children }) => ( +
+ {children} + +
+) + +const ListQuestion = ({ options, onChange, children }) => ( + +) + +const MyForm = ({values = {}}) => ( + + + What's your name ? + + + Hello {values.name}, and your country ? + + +) +``` + ## Credits The implementation of the component is based on the work of [Mary Lou from Tympanus](https://tympanus.net/Development/MinimalForm/) diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..e06a486 --- /dev/null +++ b/example/README.md @@ -0,0 +1,9 @@ +# eureka-form simple example + +this example shows how to use the `Question` and `EurekaForm` components +exported from the main package. + +## runing +```sh +yarn && yarn start +``` diff --git a/example/node_modules/eureka-form b/example/node_modules/eureka-form new file mode 120000 index 0000000..8fdb6a2 --- /dev/null +++ b/example/node_modules/eureka-form @@ -0,0 +1 @@ +../../build \ No newline at end of file diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..2768e16 --- /dev/null +++ b/example/package.json @@ -0,0 +1,16 @@ +{ + "name": "example", + "version": "0.1.0", + "private": true, + "dependencies": { + "react": "^16.4.2", + "react-dom": "^16.4.2", + "react-scripts": "1.1.5" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} \ No newline at end of file diff --git a/example/public/index.html b/example/public/index.html new file mode 100644 index 0000000..ed0ebaf --- /dev/null +++ b/example/public/index.html @@ -0,0 +1,40 @@ + + + + + + + + + + + React App + + + +
+ + + diff --git a/example/src/index.js b/example/src/index.js new file mode 100644 index 0000000..dfdeae6 --- /dev/null +++ b/example/src/index.js @@ -0,0 +1,44 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { EurekaForm, Question, Number } from '../../build'; + +class InputQuestion extends Question { + render() { + const { onChange, type, children } = this.props + return ( +
+ {children} + +
+ ) + } +} + +class ListQuestion extends Question { + render() { + const { options, onChange, children } = this.props + return ( + + ) + } +} + +const doStuff = (values) => console.log('submitted', values) + +const MyForm = ({values = {}}) => ( + + + What's your name ? + + + Hello {values.name}, and your country ? + + +) + +ReactDOM.render(, document.getElementById('root')); diff --git a/src/index.js b/src/index.js index 8b2be33..af61d97 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,22 @@ import './style.css'; import ICONS_ARROW from 'react-icons/lib/md/arrow-forward'; +const Digit = ({children, ...props}) => ( +
  • + +
  • +) + +const Number = ({value}) => ( + +) + const checkTransitionsSupport = () => { const b = document.body || document.documentElement; const s = b.style; @@ -37,13 +53,90 @@ const randomID = () => { return id; }; -class EurekaForm extends React.Component { +class Question extends React.PureComponent { constructor(props) { - super(props); + super(props) + + this.inputRef = null + } + + _validateHTML5(input) { + if (input.setCustomValidity && input.checkValidity) { + // clear any previous error messages + input.setCustomValidity(''); + + // checks input against the validation constraint + if (!input.checkValidity()) { + // Optionally, set a custom HTML5 valiation message + // comment or remove this line to use the browser default message + //input.setCustomValidity('Whoops, that\'s not an email address!'); + + // prevent the question from changing + return input.validationMessage; + } + } + return true + } + + validate() { + // XXX(xaiki): here the correct way would be to use ReactDOM to find + // `this` so we don't have to pass the node around, but that would + // introduce a new dependency, so we have this weird API where we let + // the user shoot his foot by providing us the (wrong?) ref + return this._validateHTML5(this.inputRef) + } + focus() { + this.inputRef && this.inputRef.focus() + } + + render () { + const { + children = [], + type = "text", + key, + focus, + } = this.props + + let { onChange } = this.props + + if (! onChange) { + console.error('warning you didnt pass an `onChange` handler') + onChange = function () {} + } + + return ( + + + + + + this.inputRef = e} + id={key} name={key} + onChange={onChange} + type={type} + disabled={!focus}/> + + ) + } +} + +class EurekaForm extends React.PureComponent { + constructor(props) { + super(props); + const { questions = [], children } = props + const stateQuestions = questions.map((question, i) => ( + + {question.title} + + )).concat(children) + + this.questionRefs = {} this.state = { + questions: stateQuestions, current: 0, - questions: [], values: {}, wasSubmitted: false }; @@ -53,7 +146,6 @@ class EurekaForm extends React.Component { const childQuestions = React.Children.map(this.props.children, (child, i) => ({ type: child.props.type || `eureka-question-${i}` })) - const questions = [].slice.call(this.formRef.querySelectorAll( 'ol.questions > li' )); const values = (this.props.questions || []) .concat(childQuestions) .reduce((acc, cur) => Object.assign({}, acc, { @@ -61,11 +153,8 @@ class EurekaForm extends React.Component { }), {}) this.setState({ ...this.state, - questions, values, - // XXX: this actually doesn't catch duplicate keys, - // i.e. it actually counts the *awswers* you can get. - questionsCount: Object.keys(values).length, + questionsCount: this.state.questions.length }, callback); } @@ -73,8 +162,6 @@ class EurekaForm extends React.Component { this._updateQuestions(() => { // show first question this.props.onUpdate(this.state) - const firstQuestion = this.state.questions[0]; - firstQuestion.classList.add('current'); // next question control this.ctrlNext = this.formRef.querySelector('button.next'); @@ -92,26 +179,9 @@ class EurekaForm extends React.Component { // // question number status this.questionStatus = this.formRef.querySelector('span.number'); - + // // give the questions status an id this.questionStatus.id = this.questionStatus.id || randomID(); - - // associate "x / y" with the input via aria-describedby - for (var i = this.state.questions.length - 1; i >= 0; i--) { - const formElement = this.state.questions[i].querySelector('input, textarea, select'); - formElement.setAttribute('aria-describedby', this.questionStatus.id); - }; - - // // current question placeholder - this.currentNum = this.questionStatus.querySelector('span.number-current'); - this.currentNum.innerHTML = Number(this.state.current + 1); - - // // total questions placeholder - this.totalQuestionNum = this.questionStatus.querySelector('span.number-total'); - this.totalQuestionNum.innerHTML = this.state.questionsCount; - - // // error message - this.error = this.formRef.querySelector('span.error-message'); // checks for HTML5 Form Validation support // a cleaner solution might be to add form validation to the custom Modernizr script @@ -119,107 +189,40 @@ class EurekaForm extends React.Component { // init events this._initEvents(); + this.questionRefs[this.state.current].focus() }); } _initEvents() { - // first input - const firstElInput = this.state.questions[this.state.current].querySelector('input, textarea, select'); - - // focus - const onFocusStartFn = () => { - firstElInput.removeEventListener('focus', onFocusStartFn); - - this.ctrlNext.classList.add('show'); - }; - - // show the next question control first time the input gets focused - firstElInput.addEventListener('focus', onFocusStartFn); - - if (this.props.autoFocus) { - firstElInput.focus(); - } - - // show next question - this.ctrlNext.addEventListener('click', ev => { + // show next question + this.ctrlNext.addEventListener('click', ev => { ev.preventDefault(); - this._nextQuestion(); - }); + this._nextQuestion(); + }); - // pressing enter will jump to next question - this.formRef.addEventListener('keydown', ev => { + // pressing enter will jump to next question + this.formRef.addEventListener('keydown', ev => { const keyCode = ev.keyCode || ev.which; - - // enter - if(keyCode === 13) { + + // enter + if(keyCode === 13) { ev.preventDefault(); - + this._nextQuestion(); - } - }); + } + }); } - _nextQuestion() { - if(!this._validate()) { - return false; - } - - // checks HTML5 validation - if (this.supportsHTML5Forms) { - const input = this.state.questions[this.state.current].querySelector('input, textarea, select'); - // clear any previous error messages - input.setCustomValidity(''); - - // checks input against the validation constraint - if (!input.checkValidity()) { - // Optionally, set a custom HTML5 valiation message - // comment or remove this line to use the browser default message - //input.setCustomValidity('Whoops, that\'s not an email address!'); - - // display the HTML5 error message - this._showError(input.validationMessage); - - // prevent the question from changing - return false; - } - } - - // check if form is filled - if (this.state.current === this.state.questionsCount - 1) { - this.isFilled = true; - } - - // clear any previous error messages - this._clearError(); - - // current question - const currentQuestion = this.state.questions[this.state.current]; - currentQuestion.querySelector('input, textarea, select').blur(); - this._setValue(currentQuestion) - - this.setState({ - ...this.state, - // increment current question iterator - current: ++this.state.current - }, () => { + _nextQuestionFinish() { + { // update progress bar this._progress(); - - let nextQuestion; + this.props.onUpdate(this.state) if(!this.isFilled) { - // change the current question number/status - this._updateQuestionNumber(); - // add class "show-next" to form element (start animations) this.formRef.classList.add('show-next'); - - // remove class "current" from current question and add it to the next one - // current question - nextQuestion = this.state.questions[this.state.current]; - currentQuestion.classList.remove('current'); - nextQuestion.classList.add('current'); } // after animation ends, remove class "show-next" from form element and change current question placeholder @@ -231,17 +234,10 @@ class EurekaForm extends React.Component { if(self.isFilled) { this._submit(); - } - - else { + } else { this.formRef.classList.remove('show-next'); - - this.currentNum.innerHTML = this.nextQuestionNum.innerHTML; - this.questionStatus.removeChild(this.nextQuestionNum); - - // force the focus on the next input - nextQuestion.querySelector('input, textarea, select').focus(); } + this.questionRefs[this.state.current].focus() }; // onEndTransitionFn(); @@ -252,80 +248,82 @@ class EurekaForm extends React.Component { else { onEndTransitionFn(); } - }); + } + } + + _nextQuestion() { + const component = this.questionRefs[this.state.current] + if (! component.validate) { + console.error("Warning, component", component, "doesn't support validation, implement your validate() method") + } else { + const validationResult = component.validate() + if (validationResult !== true) { + return this._showError(validationResult); + } + } + + // check if form is filled + if (this.state.current === this.state.questionsCount - 1) { + this.isFilled = true; } - // updates the progress bar by setting its width - _progress() { - const currentProgress = this.state.current * ( 100 / this.state.questionsCount ); - this.progress.style.width = currentProgress + '%'; - - // update the progressbar's aria-valuenow attribute - this.progress.setAttribute('aria-valuenow', currentProgress); + // clear any previous error messages + this._clearError(); + + this.setState(state => ({ + ...state, + // increment current question iterator + current: ++state.current + }), () => this._nextQuestionFinish()); } - - _validate() { - if (!this.state.questions[this.state.current]) { - return false; - } - // current question´s input - const input = this.state.questions[this.state.current].querySelector('input, textarea, select').value; - if (input === '') { - this._showError('EMPTYSTR'); - - return false; - } + // updates the progress bar by setting its width + _progress() { + const currentProgress = this.state.current * ( 100 / this.state.questionsCount ); + this.progress.style.width = currentProgress + '%'; - return true; + // update the progressbar's aria-valuenow attribute + this.progress.setAttribute('aria-valuenow', currentProgress); } - _updateQuestionNumber() { - // first, create next question number placeholder - this.nextQuestionNum = document.createElement('span'); - this.nextQuestionNum.className = 'number-next'; - this.nextQuestionNum.innerHTML = Number(this.state.current + 1); - - // insert it in the DOM - this.questionStatus.appendChild(this.nextQuestionNum); - } - _showError(err) { - let message = ''; - switch(err) { - case 'EMPTYSTR': - message = 'Please fill the field before continuing'; - break; - case 'INVALIDEMAIL': - message = 'Please fill a valid email address'; - break; - // ... - default: - message = err; + let message = ''; + switch(err) { + case 'EMPTYSTR': + message = 'Please fill the field before continuing'; + break; + case 'INVALIDEMAIL': + message = 'Please fill a valid email address'; + break; + // ... + default: + message = err; }; - - this.error.innerHTML = message; - - this.error.classList.add('show'); + + this.setState({ + error: message + }) } - + _clearError() { - this.error.classList.remove('show'); + this.setState({ + error: null + }) } - - _setValue(question) { - const questionInput = question.querySelector('input, textarea, select'); - questionInput.setAttribute("disabled", true); - const key = questionInput.getAttribute("id") - const newState = { - ...this.state, - values: { - ...this.state.values, - [key]: questionInput.value + + _change(key) { + return function (value) { + const { questions, current } = this.state + + const newState = { + ...this.state, + values: { + ...this.state.values, + [key]: value + } } + this.setState(newState) } - this.setState(newState) - this.props.onUpdate(newState) } _submit() { @@ -341,70 +339,59 @@ class EurekaForm extends React.Component { this.props.onSubmit(this.formRef, this.state.values); }); } - } + } render() { - let customClass = ""; - - if (this.props.className) { - customClass = this.props.className + " "; - } - - return ( -
    this.formRef = formRef}> -
    -
      - {this.props.questions && this.props.questions.map((question, i) => { - const key = question.key || `eureka-question-${i}` - return ( -
    1. - - - - - -
    2. - ) - })} - {this.props.children && React.Children.map(this.props.children, (child, i) => { - const key = child.props.type || `eureka-question-${i}` - return ( -
    3. - - - - - + const { current, error, questions, questionsCount } = this.state + const { className = "" } = this.props + let customClass = className + " "; + + + return ( + this.formRef = formRef}> +
      +
        + {questions && React.Children.map(questions, (child, i) => { + const key = child.props.type || `eureka-question-${i}` + const className = i === current + ? 'question current' + : i === current - 1 + ? 'question prev' + : i === current + 1 + ? 'question next' + : 'question' + return
      1. + { + React.cloneElement(child, { + onChange: this._change(key).bind(this), + focus: i === current ? true : false, + ref: (e) => this.questionRefs[i] = e, + key + }) + }
      2. - ) - })} -
      - - + })} +
    -
    - + -
    +
    + - - - - +
    - -
    -
    + + + {questionsCount} + - - - ) + {error && {error}} +
    + + + ) } } @@ -412,4 +399,4 @@ EurekaForm.defaultProps = { onUpdate: function () {} } -module.exports = { EurekaForm }; +module.exports = { EurekaForm, Question, Number }; diff --git a/src/style.css b/src/style.css index 2257604..878a608 100644 --- a/src/style.css +++ b/src/style.css @@ -1,91 +1,130 @@ .simform { - position: relative; - text-align: left; - font-size: 2.5em; + position: relative; + text-align: left; + font-size: 2.5em; } .simform .submit { - display: none; + display: none; +} + +.rollingNumber { + display: inline-block; + padding: 0; + margin: 0; +} + +.rollingNumber li { + display: block; + bottom: 0; + right: -4px; } /* Question list style */ .simform ol { - margin: 0; - padding: 0; - list-style: none; - position: relative; - -webkit-transition: height 0.4s; - transition: height 0.4s; + margin: 0; + padding: 0; + list-style: none; + position: relative; + -webkit-transition: height 0.4s; + transition: height 0.4s; } .simform ol:before { - content: ''; - background-color: rgba(0,0,0,0.1); - position: absolute; - left: 0; - bottom: 0; - width: 100%; - height: 2.35em; + content: ''; + background-color: rgba(0,0,0,0.1); + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 2.35em; } .questions li { - z-index: 100; - position: relative; - visibility: hidden; - height: 0; - -webkit-transition: visibility 0s 0.4s, height 0s 0.4s; - transition: visibility 0s 0.4s, height 0s 0.4s; + z-index: 100; + position: relative; + height: 0; + visibility: hidden; } .questions li.current, .no-js .questions li { - visibility: visible; - height: auto; - -webkit-transition: none; - transition: none; + visibility: visible; + height: auto; + -webkit-transition: none; + transition: none; } /* Labels */ .questions li > span { - display: block; + display: block; overflow: hidden; margin-bottom: 0.8em; } -.questions li > span label { - display: block; - -webkit-transition: -webkit-transform 0.4s; - transition: transform 0.4s; - -webkit-transform: translateY(-100%); - transform: translateY(-100%); +.questions li label { + display: block; + visibility: visible; + opacity: 0; + -webkit-transform: translateY(-100%); + transform: translateY(-100%); +} + +.questions li.current label, +.no-js .questions li label { + opacity: 1; + -webkit-transition: none; + transition: none; + -webkit-transform: translateY(-100%); + transform: translateY(-100%); } -.questions li.current > span label, -.no-js .questions li > span label { - -webkit-transition: none; - transition: none; - -webkit-transform: translateY(0); - transform: translateY(0); +.questions li.prev label { + background: green; + -webkit-animation: moveUpFromCenter 4s both; + animation: moveUpFromCenter 4s both; } -.show-next .questions li.current > span label { - -webkit-animation: moveUpFromDown 0.4s both; - animation: moveUpFromDown 0.4s both; +.questions li.current label { + background: red; + -webkit-animation: moveUpFromDown 4s both; + animation: moveUpFromDown 4s both; +} + +.questions li.next label { + background: blue; +} + +.questions li.current:first-child label { + -webkit-animation: none; + animation: none; + transform: translateY(0); } @-webkit-keyframes moveUpFromDown { - from { -webkit-transform: translateY(100%); } - to { -webkit-transform: translateY(0); } + from { -webkit-transform: translateY(100%); opacity: 0; } + to { -webkit-transform: translateY(0); opacity: 1; } } @keyframes moveUpFromDown { - from { -webkit-transform: translateY(100%); transform: translateY(100%); } - to { -webkit-transform: translateY(0); transform: translateY(0); } + from { -webkit-transform: translateY(100%); transform: translateY(100%); opacity: 0; } + to { -webkit-transform: translateY(0); transform: translateY(0); opacity: 1; } } +@-webkit-keyframes moveUpFromCenter { + from { -webkit-transform: translateY(0); opacity: 1; } + to { -webkit-transform: translateY(-100%); opacity: 0; } +} + +@keyframes moveUpFromCenter { + from { -webkit-transform: translateY(0); transform: translateY(0); opacity: 1; } + to { -webkit-transform: translateY(-100%); transform: translateY(-100%); opacity: 0; } +} + + /* Input field */ .questions input { - display: block; + display: block; margin: 0.3em 0 0 0; padding: 0.2em 1em 0.5em 0.7em; width: calc(100% - 2em); @@ -102,180 +141,156 @@ .questions .current input, .no-js .questions input { - opacity: 1; + opacity: 1; } .questions input:focus, .simform button:focus { - outline: none; + outline: none; } /* Next question button */ -.next { - position: absolute; +button.next { + position: absolute; right: 0.6em; bottom: 1.2em; - display: block; - padding: 0; - border: none; - background: none; - color: rgba(0,0,0,0.4); - text-align: center; + display: block; + padding: 0; + border: none; + background: none; + color: rgba(0,0,0,0.4); + text-align: center; opacity: 0; font-size: 30px; - z-index: 100; - cursor: pointer; - -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; - transition: transform 0.3s, opacity 0.3s; - -webkit-transform: translateX(-20%); - transform: translateX(-20%); - pointer-events: none; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + z-index: 100; + cursor: pointer; + -webkit-transition: -webkit-transform 0.3s, opacity 0.3s; + transition: transform 0.3s, opacity 0.3s; + -webkit-transform: translateX(-20%); + transform: translateX(-20%); + pointer-events: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } -.next:hover { - color: rgba(0,0,0,0.5); +button.next:hover { + color: rgba(0,0,0,0.5); } -.next.show { - opacity: 1; - -webkit-transform: translateX(0); - transform: translateX(0); - pointer-events: auto; +button.next.show { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + pointer-events: auto; } /* Progress bar */ .simform .progress { - width: 0%; - height: 0.15em; - background: rgba(0,0,0,0.3); - -webkit-transition: width 0.4s ease-in-out; - transition: width 0.4s ease-in-out; + width: 0%; + height: 0.15em; + background: rgba(0,0,0,0.3); + -webkit-transition: width 0.4s ease-in-out; + transition: width 0.4s ease-in-out; } .simform .progress::before { - position: absolute; - top: auto; - width: 100%; - height: inherit; - background: rgba(0,0,0,0.05); - content: ''; + position: absolute; + top: auto; + width: 100%; + height: inherit; + background: rgba(0,0,0,0.05); + content: ''; } /* Number indicator */ .simform .number { - position: absolute; - right: 0; - overflow: hidden; - margin: 0.4em 0; - width: 3em; - font-weight: 700; - font-size: 0.4em; + position: absolute; + right: 0; + overflow: hidden; + margin: 0.4em 0; + width: 3em; + font-weight: 700; + font-size: 0.4em; } .simform .number:after { - position: absolute; - left: 50%; - content: '/'; - opacity: 0.4; - -webkit-transform: translateX(-50%); - transform: translateX(-50%); + position: absolute; + left: 50%; + content: '/'; + opacity: 0.4; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); } .simform .number span { - float: right; - width: 40%; - text-align: center; + float: right; + width: 40%; + text-align: center; } .simform .number .number-current { - float: left; + float: left; } .simform .number-next { - position: absolute; - left: 0; + position: absolute; + left: 0; } .simform.show-next .number-current { - -webkit-transition: -webkit-transform 0.4s; - transition: transform 0.4s; - -webkit-transform: translateY(-100%); - transform: translateY(-100%); + -webkit-transition: -webkit-transform 0.4s; + transition: transform 0.4s; + -webkit-transform: translateY(-100%); + transform: translateY(-100%); } .simform.show-next .number-next { - -webkit-animation: moveUpFromDown 0.4s both; - animation: moveUpFromDown 0.4s both; + -webkit-animation: moveUpFromDown 0.4s both; + animation: moveUpFromDown 0.4s both; } /* Error and final message */ -.simform .error-message, -.simform .final-message { - position: absolute; - visibility: hidden; - opacity: 0; - -webkit-transition: opacity 0.4s; - transition: opacity 0.4s; +.simform .error-message{ + position: absolute; + -webkit-transition: opacity 0.4s; + transition: opacity 0.4s; } .simform .error-message { - padding: 0.4em 3.5em 0 0; - width: 100%; - color: rgba(0,0,0,0.7); - font-style: italic; - font-size: 0.4em; -} - -.final-message { - top: 50%; - left: 0; - padding: 0.5em; - width: 100%; - text-align: center; - -webkit-transform: translateY(-50%); - transform: translateY(-50%); -} - -.error-message.show, -.final-message.show { - visibility: visible; - opacity: 1; -} - -.final-message.show { - -webkit-transition-delay: 0.5s; - transition-delay: 0.5s; + padding: 0.4em 3.5em 0 0; + width: 100%; + color: rgba(0,0,0,0.7); + font-style: italic; + font-size: 0.4em; } /* Final hiding of form / showing message */ .simform-inner.hide { - visibility: hidden; - opacity: 0; - -webkit-transition: opacity 0.3s, visibility 0s 0.3s; - transition: opacity 0.3s, visibility 0s 0.3s; + visibility: hidden; + opacity: 0; + -webkit-transition: opacity 0.3s, visibility 0s 0.3s; + transition: opacity 0.3s, visibility 0s 0.3s; } /* No JS Fallback */ .no-js .simform { - font-size: 1.75em; + font-size: 1.75em; } .no-js .questions li { - padding: 0 0 2em; + padding: 0 0 2em; } .no-js .simform .submit { - display: block; - float: right; - padding: 10px 20px; - border: none; - background: rgba(0,0,0,0.3); - color: rgba(0,0,0,0.4); + display: block; + float: right; + padding: 10px 20px; + border: none; + background: rgba(0,0,0,0.3); + color: rgba(0,0,0,0.4); } .no-js .simform .controls { - display: none; + display: none; } /* Remove IE clear cross */ @@ -285,13 +300,13 @@ input[type=text]::-ms-clear { /* Adjust form for smaller screens */ @media screen and (max-width: 44.75em) { - .simform { - font-size: 1.8em; - } + .simform { + font-size: 1.8em; + } } @media screen and (max-width: 33.5625em) { - .simform { - font-size: 1.2em; - } -} \ No newline at end of file + .simform { + font-size: 1.2em; + } +}