animations

This commit is contained in:
2018-05-27 22:50:42 +03:00
parent c7a4e49c36
commit f03167148a
8 changed files with 101 additions and 105 deletions

54
package-lock.json generated
View File

@@ -4,6 +4,22 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.0.0-beta.49",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.49.tgz",
"integrity": "sha1-A7O/B+uYIHLI6FHdLd1RECguYb8=",
"requires": {
"core-js": "2.5.7",
"regenerator-runtime": "0.11.1"
},
"dependencies": {
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
}
}
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.0-8",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.0-8.tgz",
@@ -3252,9 +3268,9 @@
}
},
"eslint-plugin-import": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz",
"integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=",
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz",
"integrity": "sha1-2tMXgSktZmSyUxf9BJ0uKy8CIF0=",
"dev": true,
"requires": {
"contains-path": "0.1.0",
@@ -3330,9 +3346,9 @@
}
},
"eslint-plugin-jest": {
"version": "21.15.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.15.2.tgz",
"integrity": "sha512-XX0/g2F2iDnX36Ez4j5Sd8IzJj2dbDBqOxitfGD+uXyiEVECJAoRnf9eQnkzyXFVKB7DALx82ZqgqCEfeLpY7w==",
"version": "21.16.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-21.16.0.tgz",
"integrity": "sha512-pyhIbWj9RyT48q3e4A2WWec+ovn43Un3oeYIPQ1erT1PTSPJhHm9DVRtr1Vuf1GbrcFfsSROaUlkSvp6tQBGqA==",
"dev": true
},
"eslint-plugin-jsx-a11y": {
@@ -3351,9 +3367,9 @@
}
},
"eslint-plugin-react": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz",
"integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==",
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.8.2.tgz",
"integrity": "sha512-H3ne8ob4Bn6NXSN9N9twsn7t8dyHT5bF/ibQepxIHi6JiPIdC2gXlfYvZYucbdrWio4FxBq7Z4mSauQP+qmMkQ==",
"dev": true,
"requires": {
"doctrine": "2.1.0",
@@ -8970,9 +8986,9 @@
}
},
"react": {
"version": "16.3.2",
"resolved": "https://registry.npmjs.org/react/-/react-16.3.2.tgz",
"integrity": "sha512-o5GPdkhciQ3cEph6qgvYB7LTOHw/GB0qRI6ZFNugj49qJCFfgHwVNjZ5u+b7nif4vOeMIOuYj3CeYe2IBD74lg==",
"version": "16.4.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.4.0.tgz",
"integrity": "sha512-K0UrkLXSAekf5nJu89obKUM7o2vc6MMN9LYoKnCa+c+8MJRAT120xzPLENcWSRc7GYKIg0LlgJRDorrufdglQQ==",
"requires": {
"fbjs": "0.8.16",
"loose-envify": "1.3.1",
@@ -9006,9 +9022,9 @@
}
},
"react-dom": {
"version": "16.3.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.3.2.tgz",
"integrity": "sha512-MMPko3zYncNrz/7gG17wJWUREZDvskZHXOwbttzl0F0L3wDmToyuETuo/r8Y5yvDejwYcRyWI1lvVBjLJWFwKA==",
"version": "16.4.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.0.tgz",
"integrity": "sha512-bbLd+HYpBEnYoNyxDe9XpSG2t9wypMohwQPvKw8Hov3nF7SJiJIgK56b46zHpBUpHb06a1iEuw7G3rbrsnNL6w==",
"requires": {
"fbjs": "0.8.16",
"loose-envify": "1.3.1",
@@ -9212,6 +9228,14 @@
}
}
},
"react-spring": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/react-spring/-/react-spring-5.3.3.tgz",
"integrity": "sha512-5iJg9UJKEcLYEwdMpxDIzEeYwp14y5BcbLw/QckkQQBP2d7W0E3N7tIxdsE8VlPtq99kNuQvgLMn8DgH1Fl9dg==",
"requires": {
"@babel/runtime": "7.0.0-beta.49"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",

View File

@@ -8,10 +8,11 @@
"@fortawesome/react-fontawesome": "0.1.0-10",
"normalize.css": "^8.0.0",
"prop-types": "^15.6.1",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react-redux": "^5.0.7",
"react-scripts": "1.1.4",
"react-spring": "^5.3.3",
"redux": "^4.0.0",
"redux-thunk": "^2.2.0"
},
@@ -24,10 +25,10 @@
"devDependencies": {
"eslint-config-airbnb": "^16.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-jest": "^21.15.2",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jest": "^21.16.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"eslint-plugin-react": "^7.8.2",
"prettier-eslint": "^8.8.1"
}
}

View File

@@ -91,46 +91,32 @@ li:first-child .item {
text-decoration: line-through;
}
.delete {
li button {
flex-shrink: 0;
box-sizing: border-box;
padding: 0.5rem;
text-align: center;
background-color: pink;
border: none;
border-top: 1px solid #dddddd;
background: none;
text-align: left;
max-width: 2rem;
font-size: 0.75rem;
font-size: 1rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.delete {
background-color: pink;
}
.edit {
flex-shrink: 0;
box-sizing: border-box;
padding: 0.5rem;
text-align: center;
background-color: lightcyan;
border-top: 1px solid #dddddd;
max-width: 2rem;
font-size: 0.75rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.save {
flex-shrink: 0;
box-sizing: border-box;
padding: 0.5rem;
text-align: center;
background-color: lightgreen;
border-top: 1px solid #dddddd;
max-width: 2rem;
font-size: 0.75rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.todo {
@@ -145,14 +131,14 @@ li:first-child .item {
}
.todo--input {
resize: vertical;
border: none;
margin: 0;
padding: 0;
box-sizing: border-box;
word-wrap: break-word;
max-width: 100%;
flex-grow: 2;
flex-shrink: 1;
width: 100%;
max-height: 100%;
transition: 0.1s ease-in-out;
}
@@ -169,29 +155,6 @@ li:first-child .item {
animation: 0.4s collapse;
}
@keyframes create {
from {
width: 50rem;
overflow: visible;
position: relative;
padding-left: 0.5rem;
bottom: 2rem;
max-height: 0;
}
to {
overflow: hidden;
position: relative;
bottom: 0rem;
}
}
@keyframes collapse {
to {
height: 0;
max-height: 0;
}
}
.header {
display: flex;
justify-content: space-between;

View File

@@ -10,6 +10,11 @@ function Input(props) {
classes.push('no-border');
}
function submit() {
props.onClick(input.value);
input.value = '';
}
return (
<div id="inputs" className={classes.join(' ')}>
<input
@@ -19,7 +24,7 @@ function Input(props) {
id="input"
type="text"
/>
<button id="add" onClick={() => props.onClick(input.value)}>
<button id="add" onClick={() => submit()}>
add
</button>
</div>

View File

@@ -2,6 +2,7 @@ import { faTrash, faEdit, faCheck } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as React from 'react';
import PropTypes from 'prop-types';
import { animated } from 'react-spring';
class Todo extends React.Component {
constructor(props) {
@@ -61,40 +62,40 @@ class Todo extends React.Component {
if (this.state.editing) {
let input;
return (
<li>
<div className="save" onClick={() => this.stopEdit(input.value)}>
<animated.li style={this.props.style}>
<button className="save" onClick={() => this.stopEdit(input.value)}>
<FontAwesomeIcon icon={faCheck} />
</div>
</button>
<div className={todoClasses.join(' ')}>
<input
<textarea
className="todo--input"
type="text"
defaultValue={this.props.todo.text}
ref={(node) => {
input = node;
}}
/>
</div>
</li>
</animated.li>
);
}
return (
<li
<animated.li
style={this.props.style}
onMouseOver={this.onMouseOver}
onFocus={this.onMouseOver}
onMouseOut={this.onMouseOut}
onBlur={this.onMouseOut}
>
<div className={deleteClasses.join(' ')} onClick={this.props.removeTodo}>
<button className={deleteClasses.join(' ')} onClick={this.props.removeTodo}>
<FontAwesomeIcon icon={faTrash} />
</div>
<div className={editClasses.join(' ')} onClick={this.startEdit}>
</button>
<button className={editClasses.join(' ')} onClick={this.startEdit}>
<FontAwesomeIcon icon={faEdit} />
</div>
<div className={todoClasses.join(' ')} onClick={this.props.toggleTodo}>
</button>
<button className={todoClasses.join(' ')} onClick={this.props.toggleTodo}>
{this.props.todo.text}
</div>
</li>
</button>
</animated.li>
);
}
}
@@ -108,6 +109,7 @@ Todo.propTypes = {
removeTodo: PropTypes.func.isRequired,
toggleTodo: PropTypes.func.isRequired,
editTodo: PropTypes.func.isRequired,
style: PropTypes.shape({ maxHeight: PropTypes.number.isRequired }).isRequired,
};
export default Todo;

View File

@@ -1,19 +1,32 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { Transition } from 'react-spring';
import Todo from './Todo';
export default function TodosContainer(props) {
const todos = props.todos.map(todo => (
const todos = props.todos.map(todo => styles => (
<Todo
key={todo.id}
todo={todo}
style={styles}
toggleTodo={() => props.toggleTodo(todo.id)}
removeTodo={() => props.removeTodo(todo.id)}
editTodo={text => props.editTodo(todo.id, text)}
/>
));
return <ul id="list">{todos}</ul>;
return (
<ul id="list">
<Transition
keys={props.todos.map(todo => todo.id)}
from={{ maxHeight: 0 }}
enter={{ maxHeight: 100 }}
leave={{ maxHeight: 0 }}
>
{todos}
</Transition>
</ul>
);
}
TodosContainer.propTypes = {

View File

@@ -1,39 +1,27 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Input from '../components/Input';
import { addTodo } from '../actions';
import getVisibleTodos from './getVisibleTodos';
const InputContainer = props => (
<Input
inputBottomBorder={props.inputBottomBorder}
onClick={text => props.dispatch(addTodo(text))}
/>
);
InputContainer.propTypes = {
inputBottomBorder: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired,
};
function mapStateToProps(state) {
const { list } = state.lists;
try {
const listTodos = state.lists.lists[list].todos;
return {
list,
inputBottomBorder: getVisibleTodos(listTodos, state.visibilityFilter).length !== 0,
};
} catch (e) {
return {
list,
inputBottomBorder: false,
};
}
}
const InputContainerConnected = connect(mapStateToProps)(InputContainer);
function mapDispatchToProps(dispatch) {
return {
onClick: text => dispatch(addTodo(text)),
};
}
export default InputContainerConnected;
export default connect(mapStateToProps, mapDispatchToProps)(Input);

View File

@@ -21,7 +21,7 @@ export default function todos(state = { dirty: true, fetching: false, todos: []
case ADD_TODO:
return {
...state,
todos: [...state.todos, action.todo],
todos: [action.todo, ...state.todos],
};
case INVALIDATE_TODOS:
return {