Scroll text inputs into view, use red labels in text inputs when theres an error, only autocapitalize the name field

This commit is contained in:
Ken-Håvard Lieng 2018-06-03 06:18:03 +02:00
parent f5de115534
commit d2c1297cf7
12 changed files with 204 additions and 137 deletions

View file

@ -91,7 +91,7 @@ i[class*=' icon-']:before {
pointer-events: none;
user-select: none;
transform: translateZ(0);
transition: all 0.2s;
transition: all 0.2s, color 0s;
color: #777;
}

View file

@ -4,6 +4,7 @@ import Chat from 'containers/Chat';
import Connect from 'containers/Connect';
import Settings from 'containers/Settings';
import TabList from 'components/TabList';
import classnames from 'classnames';
export default class App extends Component {
handleClick = () => {
@ -24,9 +25,11 @@ export default class App extends Component {
select,
push
} = this.props;
const mainClass = showTabList
? 'main-container off-canvas'
: 'main-container';
const mainClass = classnames('main-container', {
'off-canvas': showTabList
});
return (
<div className="wrap">
{!connected && (

View file

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
import classnames from 'classnames';
import TabListItem from './TabListItem';
export default class TabList extends PureComponent {
@ -8,9 +9,12 @@ export default class TabList extends PureComponent {
render() {
const { tab, channels, servers, privateChats, showTabList } = this.props;
const className = showTabList ? 'tablist off-canvas' : 'tablist';
const tabs = [];
const className = classnames('tablist', {
'off-canvas': showTabList
});
channels.forEach(server => {
const { address } = server;
const srv = servers[address];

View file

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
import classnames from 'classnames';
export default class TabListItem extends PureComponent {
handleClick = () => {
@ -8,25 +9,16 @@ export default class TabListItem extends PureComponent {
render() {
const { target, content, selected, connected } = this.props;
const classes = [];
const style = {};
if (!target) {
classes.push('tab-server');
if (connected) {
classes.push('success');
} else {
classes.push('error');
}
}
if (selected) {
classes.push('selected');
}
const className = classnames({
'tab-server': !target,
success: !target && connected,
error: !target && !connected,
selected
});
return (
<p className={classes.join(' ')} style={style} onClick={this.handleClick}>
<p className={className} onClick={this.handleClick}>
<span className="tab-content">{content}</span>
</p>
);

View file

@ -1,13 +1,16 @@
import React, { PureComponent } from 'react';
import classnames from 'classnames';
export default class Message extends PureComponent {
handleNickClick = () => this.props.onNickClick(this.props.message.from);
render() {
const { message } = this.props;
const className = message.type
? `message message-${message.type}`
: 'message';
const className = classnames('message', {
[`message-${message.type}`]: message.type
});
const style = {
paddingLeft: `${window.messageIndent + 15}px`,
textIndent: `-${window.messageIndent}px`,

View file

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
import classnames from 'classnames';
import Editable from 'components/ui/Editable';
import { isValidNick } from 'utils';
@ -51,14 +52,13 @@ export default class MessageInput extends PureComponent {
onNickChange,
onNickEditDone
} = this.props;
return (
<div className="message-input-wrap">
<Editable
className={
isValidNick(nick)
? 'message-input-nick'
: 'message-input-nick invalid'
}
className={classnames('message-input-nick', {
invalid: !isValidNick(nick)
})}
value={nick}
onBlur={onNickEditDone}
onChange={onNickChange}

View file

@ -1,6 +1,7 @@
import React, { PureComponent } from 'react';
import { List } from 'react-virtualized/dist/commonjs/List';
import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
import classnames from 'classnames';
import UserListItem from './UserListItem';
export default class UserList extends PureComponent {
@ -29,7 +30,10 @@ export default class UserList extends PureComponent {
render() {
const { users, showUserList } = this.props;
const className = showUserList ? 'userlist off-canvas' : 'userlist';
const className = classnames('userlist', {
'off-canvas': showUserList
});
return (
<div className={className}>

View file

@ -73,7 +73,7 @@ class Connect extends Component {
form = (
<Form className="connect-form">
<h1>Connect</h1>
<TextInput name="name" placeholder="Name" />
<TextInput name="name" placeholder="Name" autoCapitalize="words" />
<div className="connect-form-address">
<TextInput name="host" placeholder="Host" />
<TextInput name="port" type="number" placeholder="Port" />

View file

@ -1,30 +1,80 @@
import React from 'react';
import React, { PureComponent } from 'react';
import { Field } from 'formik';
import classnames from 'classnames';
const TextInput = ({ name, placeholder, ...props }) => (
<Field
name={name}
render={({ field }) => (
<div className="textinput">
<input
className={field.value ? 'value' : null}
type="text"
name={name}
autoCorrect="off"
autoComplete="off"
spellCheck="false"
{...field}
{...props}
/>
<span className={field.value ? 'textinput-1 value' : 'textinput-1'}>
{placeholder}
</span>
<span className={field.value ? 'textinput-2 value' : 'textinput-2'}>
{placeholder}
</span>
</div>
)}
/>
);
export default class TextInput extends PureComponent {
constructor(props) {
super(props);
this.input = React.createRef();
window.addEventListener('resize', this.handleResize);
}
export default TextInput;
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}
handleResize = () => {
if (this.scroll) {
this.scroll = false;
this.scrollIntoView();
}
};
handleFocus = () => {
this.scroll = true;
setTimeout(() => {
this.scroll = false;
}, 2000);
};
scrollIntoView = () => {
if (this.input.current.scrollIntoViewIfNeeded) {
this.input.current.scrollIntoViewIfNeeded();
} else {
this.input.current.scrollIntoView();
}
};
render() {
const { name, placeholder, ...props } = this.props;
return (
<Field
name={name}
render={({ field, form }) => (
<div className="textinput">
<input
className={field.value && 'value'}
type="text"
name={name}
autoCapitalize="off"
autoCorrect="off"
autoComplete="off"
spellCheck="false"
ref={this.input}
onFocus={this.handleFocus}
{...field}
{...props}
/>
<span
className={classnames('textinput-1', {
value: field.value,
error: form.touched[name] && form.errors[name]
})}
>
{placeholder}
</span>
<span
className={classnames('textinput-2', {
value: field.value,
error: form.touched[name] && form.errors[name]
})}
>
{placeholder}
</span>
</div>
)}
/>
);
}
}