React

by mikolalex

HTML

<script src="https://unpkg.com/mrr@1.3.5/dist/bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.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;
	}

React

const { createMrrApp } = mrr;
const { pipe, prop, identity, not, always, inc, assoc, map, apply, filter, __, useWith, unapply, equals } = R;

// mrrApp.js

const todos = localStorage.getItem('todos') ? JSON.parse(localStorage.getItem('todos')) : [];

const { withMrr, skip } = createMrrApp({
    macros: {
        // add your custom macros here
    },
    globalGrid: {
        $init: {
            todos,
        },
        todos: ['coll', {
            create: '*/addNewTodoItem',
            update: ['merge',
              '*/updateTodoItems',
              [completed => ([{ completed }, {}]), '*/toggleTodosStatus']],
            delete: ['merge',
              [always({ completed: true }), '*/clearCompletedTodos'],
              '*/removeTodoItems'],
        }],
        toLS: [arr => localStorage.setItem('todos', JSON.stringify(arr)), 'todos'],
    },
});



// Todo.js

const id = identity;
const ifPressed = key => e => e.key == key || skip;

const TodoItem = withMrr({
  //$log: true,
  $expose: {
    'removeTodoItems': 'remove',
    'updateTodoItems': 'changes',   
  },
  i: [prop('i'), '$props', '$start'],
  isEdited: ['toggle', 'startEdit', 'finishEdit'],
  changes: ['merge',
    [(completed, i) => [{ completed }, i], 'complete', '-i'],
    [(text, i) => [{ text }, i], 'afterEdit.update', '-i'],
  ],
  afterEdit: ['split', {
    'remove': not,
    'update': identity,
  }, '-newText', 'finishEdit'],
  remove: [prop('i'), '$props', ['merge', 'afterEdit.remove', 'removeItem']],
}, (state, props, $) => ( <div className="todo-item">
   <input type="checkbox" checked={ props.completed } onChange={ $('complete', !props.completed) }  />
   <div className="remove">
    <a onClick={ $('removeItem') }>Remove</a>
   </div>
   { state.isEdited
     ? <div className="text"><input 
	     defaultValue={ props.text } 
	     onChange={ $("newText") }
	     onKeyPress={ $('finishEdit', ifPressed('Enter')) } /></div>
     : <div className="text" onClick={ $("startEdit") }>{...