diff --git a/src/components/atoms/Form/FormHelp.module.scss b/src/components/atoms/Form/FormHelp.module.scss new file mode 100644 index 0000000..b518260 --- /dev/null +++ b/src/components/atoms/Form/FormHelp.module.scss @@ -0,0 +1,7 @@ +@import '../../../styles/variables'; + +.help { + font-size: $font-size-small; + color: darken($brand-grey-light, 10%); + margin-top: $spacer / 4; +} diff --git a/src/components/atoms/Form/FormHelp.test.js b/src/components/atoms/Form/FormHelp.test.js new file mode 100644 index 0000000..a82f58d --- /dev/null +++ b/src/components/atoms/Form/FormHelp.test.js @@ -0,0 +1,13 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import FormHelp from './FormHelp' + +it('FormHelp renders without crashing', () => { + const div = document.createElement('div') + ReactDOM.render( + Price of your data set asset in Ocean Tokens., + div + ) + ReactDOM.unmountComponentAtNode(div) +}) diff --git a/src/components/atoms/Form/FormHelp.tsx b/src/components/atoms/Form/FormHelp.tsx new file mode 100644 index 0000000..ea4d739 --- /dev/null +++ b/src/components/atoms/Form/FormHelp.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import styles from './FormHelp.module.scss' + +const FormHelp = ({ children }: { children: string }) => ( +
{children}
+) + +export default FormHelp diff --git a/src/components/atoms/Form/FormInput.module.scss b/src/components/atoms/Form/FormInput.module.scss new file mode 100644 index 0000000..bd363ac --- /dev/null +++ b/src/components/atoms/Form/FormInput.module.scss @@ -0,0 +1,177 @@ +@import '../../styles/variables'; + +.formGroup { + margin-bottom: $spacer; +} + +.input-wrap { + background: $brand-gradient; + border-radius: $border-radius; + width: 100%; + padding: 2px; + display: flex; + position: relative; + + &.is-focused { + background: $brand-black; + } + + .is-dimmed & { + background: $brand-grey-lighter; + + &.is-focused { + background: $brand-grey-light; + } + } +} + +.input-wrap-search { + .input { + padding-left: $spacer * 1.25; + } + + svg { + position: absolute; + left: $spacer / 3; + width: 1.25rem; + height: 1.25rem; + top: 50%; + margin-top: -.75rem; + fill: rgba($brand-grey-light, .7); + } +} + +.input { + font-size: $font-size-base; + font-family: $font-family-button; + color: $brand-black; + border: none; + box-shadow: none; + width: 100%; + background: $brand-white; + padding: $spacer / 3; + margin: 0; + border-radius: $border-radius; + transition: .2s ease-out; + min-height: 43px; + appearance: none; + + &:focus { + border: none; + box-shadow: none; + outline: 0; + } + + &::placeholder { + font-family: $font-family-base; + font-size: $font-size-base; + color: $brand-grey-light; + font-weight: $font-weight-base; + transition: .2s ease-out; + opacity: .7; + } + + &[readonly], + &[disabled] { + background-color: $brand-grey-lighter; + cursor: not-allowed; + pointer-events: none; + } + + // &::-webkit-credentials-auto-fill-button, + // &::-webkit-caps-lock-indicator { + // background: $brand-white; + // } + + // &:-webkit-autofill, + // &:-webkit-autofill:hover, + // &:-webkit-autofill:focus { + // -webkit-text-fill-color: $brand-white; + // box-shadow: 0 0 0 1000px $brand-black inset; + // transition: background-color 5000s ease-in-out 0s; + // } +} + +// stylelint-disable-next-line +select.input { + height: 43px; + padding-right: 3rem; + border: 0; + + // custom arrow + // stylelint-disable + background-image: linear-gradient(45deg, transparent 50%, $brand-purple 50%), + linear-gradient(135deg, $brand-purple 50%, transparent 50%), + linear-gradient( + to right, + $brand-pink 1px, + lighten($brand-grey-lighter, 5%) 2px, + lighten($brand-grey-lighter, 5%) + ); + background-position: calc(100% - 18px) calc(1rem + 5px), + calc(100% - 13px) calc(1rem + 5px), 100% 0; + background-size: 5px 5px, 5px 5px, 2.5rem 3rem; + // stylelint-enable + background-repeat: no-repeat; + + &:focus { + outline: 0; + font-family: $font-family-base; + } + // stylelint-disable + .is-dimmed & { + background-image: linear-gradient( + 45deg, + transparent 50%, + $brand-grey-light 50% + ), + linear-gradient(135deg, $brand-grey-light 50%, transparent 50%), + linear-gradient( + to right, + $brand-grey-lighter 1px, + lighten($brand-grey-lighter, 5%) 2px, + lighten($brand-grey-lighter, 5%) + ); + } + // stylelint-enable +} + +.label { + color: $brand-grey; + font-size: $font-size-base; + font-family: $font-family-title; + line-height: 1.2; + display: block; + margin-bottom: $spacer / 6; + + &.is-required { + &:after { + content: '*'; + font-size: $font-size-base; + color: $brand-grey-light; + display: inline-block; + margin-left: .1rem; + } + } +} + +// Size modifiers +.input-sm { + font-size: $font-size-small; + min-height: 32px; + padding: $spacer / 4; + + &::placeholder { + font-size: $font-size-small; + } +} + +// stylelint-disable-next-line +select.input-sm { + height: 32px; + padding-right: 2rem; + + // custom arrow + background-position: calc(100% - 14px) 1rem, calc(100% - 9px) 1rem, 100% 0; + background-size: 5px 5px, 5px 5px, 2rem 3rem; +} diff --git a/src/components/atoms/Form/FormInput.tsx b/src/components/atoms/Form/FormInput.tsx new file mode 100644 index 0000000..ae279e9 --- /dev/null +++ b/src/components/atoms/Form/FormInput.tsx @@ -0,0 +1,88 @@ +import React, { PureComponent } from 'react' +import { ReactComponent as SearchIcon } from '../../../svg/search.svg' +import FormHelp from './FormHelp' +import styles from './FormInput.module.scss' + +interface IFormInputProps { + name: string + label: string + placeholder: string + required?: boolean + help?: string + tag?: string + type: string + small?: boolean + additionalComponent?: void +} + +interface IFormInputState { + isFocused: boolean +} + +export default class FormInput extends PureComponent< + IFormInputProps, + IFormInputState +> { + public state: IFormInputState = { isFocused: false } + + public inputWrapClasses() { + if (this.props.type === 'search') { + return 'input-wrap input-wrap-search' + } else if (this.props.type === 'search' && this.state.isFocused) { + return 'input-wrap input-wrap-search is-focused' + } else if (this.state.isFocused && this.props.type !== 'search') { + return 'input-wrap is-focused' + } else { + return 'input-wrap' + } + } + + public handleBlur() { + this.setState({ isFocused: true }) + } + + public handleFocus() { + this.setState({ isFocused: false }) + } + + public render() { + const { + name, + label, + required, + type, + help, + small, + additionalComponent, + ...props + } = this.props + + return ( +
+ +
+ + {type === 'search' && } +
+ {help && {help}} + + {additionalComponent && additionalComponent} +
+ ) + } +}