div#bob
div#alice
IO streams effectively channel interactions between isolated components.
let _r = __.record(), IO = dom.IO; // : Model let M = { user: 'alice', msgs: [], input: '' } // read : Model -> [Msg] let read = M => M.msgs .map(_r.set('user', M.user)); // send : Model -> Msg let send = M => ({ sender: M.user, date: Date.now(), body: M.input }); //------ Server ------ let server = {}; // .msgs : [Msg] server.msgs = [{ sender: 'alice', date: 0, body: 'I love you Bob' }]; // .clients : [IO(e)] server.clients = []; // .post : Msg -> ServerEffect server.post = msg => { server.msgs.push(msg); server.clients.forEach( io => io.channel('msg', msg) ); } // .join : User -> ServerEffect server.join = user => server.clients.push( client(user, server) ); //------ Client ------ // client : (User, Server) -> IO(e) let client = (user, server) => client.app.start({ user, msgs: server.msgs, input: '' }); // .app : e -> State(Model, IO(e)) client.app = dom.app() .on('start', st => st .reads(IO.put(view.main)) ) .on('input', (st, text) => st .set('input', text) .return(IO()) ) .on('msg', (st, msg) => st .streamline({msgs: M => [...M.msgs, msg]}) .reads(read) .push(IO.map(view.msg).put([-1])) ) .on('send', st => st .set('input', '') .reads(IO.replace(view.input)) ) .hook('send', st => st .reads(send) .push(msg => () => server.post(msg)) ); //------ View ------ let view = {}; // .msg : Msg -> Node view.msg = dom(':msg > msgs', [ ['.msg-head', [ ['.sender', { html: m => m.sender === m.user ? 'you say:' : m.sender + ' says:' }], ['.date', {html: m => `on 1 Jan. 1970 and ${m.date} ms`}] ]], ['.msg-body', { html: m => m.body, class: m => m.sender === m.user ? 'sent' : 'received' }] ]); // .msgs : Model -> [Node] view.msgs = dom(':msgs') .pull(read) .branch(dom.map(view.msg)) // .input : Model -> Node view.input = dom(':input', [ ['textarea', { onkeyup: (e, io) => io.channel('input', e.target.value) }], ['button', { html: 'Send', onclick: (e, io) => io.channel('send') }] ]); // .main : Model -> Node view.main = dom('.chat') .append(view.msgs, view.input) .put(M => '#' + M.user); //------ Start a romance ------ ['alice', 'bob'].forEach(server.join);