--- /dev/null
+import React from 'react'
+import pick from 'lodash/pick'
+import styles from './PasswordField.scss'
+import { FieldLabel } from 'features/shared/components'
+import disableAutocomplete from 'utility/disableAutocomplete'
+
+const TEXT_FIELD_PROPS = [
+ 'value',
+ 'onBlur',
+ 'onChange',
+ 'onFocus',
+ 'name'
+]
+
+class PasswordField extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = {
+ capLock: false
+ }
+ }
+
+ render() {
+ const fieldProps = pick(this.props.fieldProps, TEXT_FIELD_PROPS)
+ const {touched, error} = this.props.fieldProps
+
+ const capLock = (e) => {
+ const charCode = e.charCode || e.which
+ const isShift = e.shiftKey ||(charCode == 16 ) || false
+ const visibility = ((charCode >= 65 && charCode <= 90) && !isShift) ||
+ ((charCode >= 97 && charCode <= 122) && isShift)
+ this.setState({capLock: visibility})
+ }
+
+ return(
+ <div className='form-group'>
+ {this.props.title && <FieldLabel>{this.props.title}</FieldLabel>}
+ <input className={`form-control ${styles.password} ${this.state.capLock? styles.capsIconGreen: styles.capsIcon}`}
+ type='password'
+ placeholder={this.props.placeholder}
+ autoFocus={!!this.props.autoFocus}
+ onKeyPress={capLock}
+ {...disableAutocomplete}
+ {...fieldProps} />
+
+ {touched && error && <span className='text-danger'><strong>{error}</strong></span>}
+ {this.props.hint && <span className='help-block'>{this.props.hint}</span>}
+ </div>
+ )
+ }
+}
+
+export default PasswordField
--- /dev/null
+.capsIcon{
+ background-image: url('images/capslock.svg');
+}
+
+.capsIconGreen{
+ background-image: url('images/capslock-green.svg');
+}
+
+.password{
+ background-repeat: no-repeat;
+ background-position: 99% center;
+ background-size: 20px 20px;
+ padding-right: 30px;
+}
import PageContent from './PageContent/PageContent'
import PageTitle from './PageTitle/PageTitle'
import PaginationField from './Pagination/PaginationField'
+import PasswordField from './PasswordField/PasswordField'
import RawJsonButton from './RawJsonButton'
import RelativeTime from './RelativeTime'
import RoutingContainer from './RoutingContainer'
PageContent,
PageTitle,
PaginationField,
+ PasswordField,
RawJsonButton,
RelativeTime,
RoutingContainer,
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 30 30">
+ <defs>
+ <style>
+ .cls-1 {
+ clip-path: url(#clip-大写_3);
+ }
+
+ .cls-2 {
+ fill: #00bfa9;
+ }
+ </style>
+ <clipPath id="clip-大写_3">
+ <rect width="30" height="30"/>
+ </clipPath>
+ </defs>
+ <g id="大写_3" data-name="大写 – 3" class="cls-1">
+ <path id="Union_85" data-name="Union 85" class="cls-2" d="M-2240.041-318.8v-3.233h8.081v3.233Zm0-5.657V-331H-2244l8-8,8,8h-3.959v6.546Z" transform="translate(2251 343.398)"/>
+ </g>
+</svg>
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 30 30">
+ <defs>
+ <style>
+ .cls-1 {
+ clip-path: url(#clip-capslocks_2);
+ }
+
+ .cls-2 {
+ fill: #e4e4e4;
+ }
+ </style>
+ <clipPath id="clip-capslocks_2">
+ <rect width="30" height="30"/>
+ </clipPath>
+ </defs>
+ <g id="capslocks_2" data-name="capslocks – 2" class="cls-1">
+ <path id="Union_86" data-name="Union 86" class="cls-2" d="M-2140.041-318.8v-3.233h8.081v3.233Zm0-5.657V-331H-2144l8-8,8,8h-3.959v6.546Z" transform="translate(2151 343.398)"/>
+ </g>
+</svg>