all imlementations using Cyclow all imlementations of Composition

an es6 implementation
of the Composition demo using Cyclow



import {Block} from 'cyclow'

const viewConfirm = () => [
  {tag: 'button', content: 'Confirm', on: {click: 'confirm'}},
  {tag: 'button', content: 'Cancel', on: {click: 'cancel'}}
]

const viewDefault = mode => ({
  tag: 'button',
  content: 'Submit',
  attrs: {disabled: mode === 'disabled'},
  on: {click: 'maybe'}
})

const Confirm = () => Block({
  inputs: ['disabled'],
  outputs: ['confirmation'],
  on: {
    init: () => state => ({mode: 'disabled'}),
    disabled: (disabled, {mode}) => {
      if (disabled) {
        return state => ({mode: 'disabled'})
      } else if (mode === 'disabled') {
        return state => ({mode: 'waiting'})
      }
    },
    maybe: () => state => ({mode: 'confirm'}),
    cancel: () => state => ({mode: 'waiting'}),
    confirm: () => [state => ({mode: 'waiting'}), ['out.confirmation']]
  },
  view: ({mode}) => mode === 'confirm' ? viewConfirm() : viewDefault(mode)
})

export default Confirm

The same file in a TypeScript implementation using Angular (2.4.9):

import {Component,Input,Output,EventEmitter} from '@angular/core';

@Component({
  selector: 'confirm',
  template: `
    <span *ngIf="mode !== 'confirm'">
      <button (click)="maybe()" [disabled]="mode === 'disabled'">Submit</button>
    </span>
    <span *ngIf="mode === 'confirm'">
      <button (click)="changedmymind()">Cancel</button>
      <button (click)="yesimsure()">Confirm</button>
    </span>
  `
})
export class Confirm {
  mode: string = 'waiting'
  @Output() confirm = new EventEmitter<void>()
  @Input() set disabled(bool: boolean){
    this.mode = bool ? 'disabled' : 'waiting'
  }
  maybe() { this.mode = 'confirm' }
  changedmymind() { this.mode = 'waiting' }
  yesimsure() {
    this.confirm.emit()
    this.mode = 'waiting'
  }
}

The same file in a composition helper implementation using CycleJS (10.0.5):

import {span, button} from '@cycle/dom'
import xs from 'xstream'

const intent = sources => xs.merge(
  sources.disabled$.map(i => i ? 'DISABLE' : 'ENABLE'),
  sources.DOM.select('.maybe').events('click').map(i => 'MAYBE'),
  sources.DOM.select('.cancel').events('click').map(i => 'CANCEL'),
  sources.DOM.select('.confirm').events('click').map(i => 'CONFIRM')
)

const model = action$ => action$.fold((s, action) => {
  switch (action) {
    case 'DISABLE': return 'disabled'
    case 'MAYBE': return 'confirm'
    case 'ENABLE': return s === 'disabled' ? 'waiting' : s
    default: return 'waiting'
  }
}, 'disabled')

const view = state$ => state$.map(state => state === 'confirm'
  ? span([button('.confirm', 'Confirm'), button('.cancel', 'Cancel')])
  : button('.maybe', {attrs: {disabled: state === 'disabled'}}, 'Submit')
)

export default sources => {
  const action$ = intent(sources)
  const state$ = model(action$)
  const vtree$ = view(state$)
  return {
    DOM: vtree$,
    confirm$: action$.filter(i => i === 'CONFIRM')
  }
}

The same file in a createClass implementation using React (15.2.0):

import React from 'react'

let Confirm = React.createClass({
  getInitialState: () => ({mode: 'waiting'}),
  maybe () { this.setState({mode: 'confirm'}) },
  changedmymind () { this.setState({mode: 'waiting'}) },
  yesimsure () {
    this.props.confirm()
    this.setState({mode: 'waiting'})
  },
  render () {
    return this.state.mode !== 'confirm'
    ? <button onClick={this.maybe} disabled={this.props.disabled}>Submit</button>
    : <span>
      <button onClick={this.changedmymind}>Cancel</button>
      <button onClick={this.yesimsure}>Confirm</button>
    </span>
  }
})

export default Confirm