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]) }  />
    ...