Mrr Todo list shortest example
by mikolalex
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bundle.js"></script>
<div id="app"></div>
CSS
body {
padding: 10px;
}
.options {
margin: 0;
padding: 0;
display: inline-block;
}
.todo-item {
border: 1px dotted grey;
padding: 10px;
margin: 10px 0;
}
.remove {
float: right;
}
.remove, .clear-completed, .options li {
color: blue;
text-decoration: underline;
display: inline-block;
margin: 0 5px;
cursor: pointer;
}
.options li.active {
border: 1px dotted grey;
color: black;
padding: 3px;
text-decoration: none;
}
.text {
display: inline-block;
padding: 0 10px;
}
.todo-app > * {
margin: 20px 0;
}
Babel + JSX
const { withMrr, skip } = mrr;
const { pipe, prop, not, always, assoc, filter, __, equals } = R;
const todos = localStorage.getItem('todos') ? JSON.parse(localStorage.getItem('todos')) : [{
completed: false,
text: 'Save the world',
}, {
completed: true,
text: 'Have a beer',
}];
const ifPressed = key => e => e.key == key || skip;
const hashMap = {
all: '*',
completed: false,
active: true,
}
const get_hash = () => hashMap[window.location.hash.replace('#/', '')];
const Todos = withMrr({
$init: { todos },
newTodoItem: [assoc('text', __, { completed: false }), '-newInput', 'addNewTodo'],
newInput: [always(''), 'newTodoItem'],
todos: ['coll', {
create: 'newTodoItem',
update: ['merge',
'setCompleted',
'afterEdit.update',
[completed => ([{ completed }, {}]), 'toggleCompleted']],
delete: ['merge',
'removeItem',
[always({ completed: true }), 'clearCompleted'],
'afterEdit.remove'],
}],
isEdited: ['merge',
'startEdit',
[always(false), 'afterEdit.remove', 'afterEdit.update']
],
afterEdit: ['split', {
'remove': (text, i) => !text && i,
'update': (text, i) => text && [{ text }, i],
}, '-newText', '-isEdited', 'finishEdit'],
show: ['async', cb => {
window.addEventListener('hashchange', () => cb(get_hash()));
cb(get_hash());
}, '$start'],
shownTodos: [(a, val) => a.filter(pipe(prop('completed'), equals(val), not)), 'todos', 'show', '$start'],
openNumber: [pipe(filter(pipe(prop('completed'), not)), prop('length')), 'todos', '$start'],
toLS: [arr => localStorage.setItem('todos', JSON.stringify(arr)), 'todos'],
}, (state, props, $) => {
return (
<div className="todo-app">
<div>
<h1>Todos</h1>
{ state.shownTodos && state.shownTodos.map((todo, i) => (
<div className="todo-item">
<input type="checkbox" checked={ todo.completed } onChange={ $('setCompleted', [{ completed: !todo.completed }, i]) } />
...