text: import React from "react";
  import { observe } from "frint-react";
  import { Observable } from "rxjs/Observable";
  import { concatMap } from "rxjs/operator/concatMap";
  import { map } from "rxjs/operator/map";
  import { merge } from "rxjs/operator/merge";
  import { scan } from "rxjs/operator/scan";
  import PropTypes from "prop-types";
  
  import { changeColor } from "../actions/color";
  
  import {
    GREEN_COLOR,
    RED_COLOR,
    ORANGE_COLOR,
    CHANGE_COLOR_ASYNC,
  } from "../constants";
  
  class Root extends React.Component {
    static propTypes = {
      color: PropTypes.string,
      counter: PropTypes.number,
      incrementCounter: PropTypes.func,
      decrementCounter: PropTypes.func,
      changeColor: PropTypes.func,
      changeColorAsync: PropTypes.func,
      regionProps: PropTypes.object,
      foo: PropTypes.object,
      bar: PropTypes.object,
      baz: PropTypes.object,
    };
  
    render() {
      const codeStyle = {
        color: this.props.color,
        backgroundColor: this.props.color,
      };
  
      return (
        <div>
          <h5>App: Color</h5>
  
          <p>
            Color value in <strong>ColorApp</strong>:{" "}
            <code style={codeStyle}>{this.props.color}</code>
          </p>
  
          <div>
            <button
              className="button"
              onClick={() => this.props.changeColor(GREEN_COLOR)}
              style={{ backgroundColor: GREEN_COLOR, color: "#fff" }}
            >
              Green
            </button>
  
            <button
              className="button"
              onClick={() => this.props.changeColor(RED_COLOR)}
              style={{ backgroundColor: RED_COLOR, color: "#fff" }}
            >
              Red
            </button>
  
            <button
              className="button"
              onClick={() => this.props.changeColorAsync(ORANGE_COLOR)}
              style={{ backgroundColor: ORANGE_COLOR, color: "#fff" }}
            >
              Async
            </button>
          </div>
  
          <p>
            Counter value from <strong>CounterApp</strong>:{" "}
            <code>{this.props.counter}</code>
          </p>
  
          <p>
            <a href="#" onClick={() => this.props.incrementCounter()}>
              Increment
            </a>{" "}
            counter from here.
          </p>
  
          <div>
            <p>
              <strong>Region Props:</strong>
            </p>
  
            <pre>
              <code>{JSON.stringify(this.props.regionProps, null, 2)}</code>
            </pre>
          </div>
  
          <div>
            <p>
              <strong>Services:</strong>
            </p>
  
            <ul>
              <li>
                <strong>Foo</strong> (cascaded): is from{" "}
                <code>{this.props.foo.getAppName()}</code>
              </li>
              <li>
                <strong>Bar</strong> (cascaded and scoped): is from{" "}
                <code>{this.props.bar.getAppName()}</code>
              </li>
              <li>
                <strong>Baz</strong> (not cascaded): is unavaialble -{" "}
                <code>{this.props.baz}</code>
              </li>
            </ul>
          </div>
        </div>
      );
    }
  }
  
  export default observe(function (app) {
    // eslint-disable-line func-names
    // self
    const store = app.get("store");
    const region = app.get("region");
  
    const state$ = store.getState$()::map((state) => {
      return {
        color: state.color.value,
      };
    });
  
    const regionProps$ = region.getProps$()::map((regionProps) => {
      return {
        regionProps,
      };
    });
  
    const actions$ = Observable.of({
      changeColor: (...args) => {
        return store.dispatch(changeColor(...args));
      },
      changeColorAsync: (color) => {
        return store.dispatch({
          type: CHANGE_COLOR_ASYNC,
          color,
        });
      },
    });
  
    const services$ = Observable.of({
      foo: app.get("foo"),
      bar: app.get("bar"),
      baz: app.get("baz"),
    });
  
    // other app: CounterApp
    const counterApp$ = app.getAppOnceAvailable$("CounterApp");
    const counterAppState$ = counterApp$
      ::concatMap((counterApp) => {
        return counterApp.get("store").getState$();
      })
      ::map((counterState) => {
        return {
          counter: counterState.counter.value,
        };
      });
  
    const counterAppActions$ = counterApp$::map((counterApp) => {
      const counterStore = counterApp.get("store");
      return {
        incrementCounter: () => {
          return counterStore.dispatch({ type: "INCREMENT_COUNTER" });
        },
      };
    });
  
    // combine them all into props
    return state$
      ::merge(regionProps$)
      ::merge(actions$)
      ::merge(services$)
      ::merge(counterAppState$)
      ::merge(counterAppActions$)
      ::scan(
        (props, emitted) => {
          return {
            ...props,
            ...emitted,
          };
        },
        {
          // default props to start with
          counter: 0,
        }
      );
  })(Root);
  