text: /* eslint-disable no-fallthrough, react/react-in-jsx-scope, react/jsx-no-undef */
  /* global React ReactCache ReactDOM SchedulerTracing ScheduleTracing  */
  
  const apps = [];
  
  const pieces = React.version.split('.');
  const major = pieces[0] === '0' ? parseInt(pieces[1], 10) : parseInt(pieces[0], 10);
  const minor = pieces[0] === '0' ? parseInt(pieces[2], 10) : parseInt(pieces[1], 10);
  
  // Convenience wrapper to organize API features in DevTools.
  function Feature({ children, label, version }) {
    return (
      <div className="Feature">
        <div className="FeatureHeader">
          <code className="FeatureCode">{label}</code>
          <small>{version}</small>
        </div>
        {children}
      </div>
    );
  }
  
  // Simplify interaction tracing for tests below.
  let trace = null;
  if (typeof SchedulerTracing !== 'undefined') {
    trace = SchedulerTracing.unstable_trace;
  } else if (typeof ScheduleTracing !== 'undefined') {
    trace = ScheduleTracing.unstable_trace;
  } else {
    trace = (_, __, callback) => callback();
  }
  
  // https://github.com/facebook/react/blob/master/CHANGELOG.md
  switch (major) {
    case 16:
      switch (minor) {
        case 7:
          // Hooks
          function Hooks() {
            const [count, setCount] = React.useState(0);
            const incrementCount = React.useCallback(
              () => setCount(count + 1),
              [count]
            );
            return (
              <div>
                count: {count} <button onClick={incrementCount}>increment</button>
              </div>
            );
          }
          apps.push(
            <Feature key="Hooks" label="Hooks" version="16.7+">
              <Hooks />
            </Feature>
          );
        case 6:
          // memo
          function LabelComponent({label}) {
            return <label>{label}</label>;
          }
          const AnonymousMemoized = React.memo(({label}) => <label>{label}</label>);
          const Memoized = React.memo(LabelComponent);
          const CustomMemoized = React.memo(LabelComponent);
          CustomMemoized.displayName = 'MemoizedLabelFunction';
          apps.push(
            <Feature key="memo" label="memo" version="16.6+">
              <AnonymousMemoized label="AnonymousMemoized" />
              <Memoized label="Memoized" />
              <CustomMemoized label="CustomMemoized" />
            </Feature>
          );
  
          // Suspense
          const loadResource = ([text, ms]) => {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                resolve(text);
              }, ms);
            });
          };
          const getResourceKey = ([text, ms]) => text;
          const Resource = ReactCache.unstable_createResource(loadResource, getResourceKey);
          class Suspending extends React.Component {
            state = {useSuspense: false};
            useSuspense = () => this.setState({useSuspense: true});
            render() {
              if (this.state.useSuspense) {
                const text = Resource.read(['loaded', 2000]);
                return text;
              } else {
                return (
                  <button onClick={this.useSuspense}>
                    load data
                  </button>
                );
              }
            }
          }
          apps.push(
            <Feature key="Suspense" label="Suspense" version="16.6+">
              <React.Suspense fallback={<div>loading...</div>}>
                <Suspending />
              </React.Suspense>
            </Feature>
          );
  
          // lazy
          const LazyWithDefaultProps = React.lazy(() => new Promise(resolve => {
            function FooWithDefaultProps(props) {
              return <h1>{props.greeting}, {props.name}</h1>;
            }
            FooWithDefaultProps.defaultProps = {
              name: 'World',
              greeting: 'Bonjour',
            };
            resolve({
              default: FooWithDefaultProps,
            });
          }));
          apps.push(
            <Feature key="lazy" label="lazy" version="16.6+">
              <React.Suspense fallback={<div>loading...</div>}>
                <LazyWithDefaultProps greeting="Hello" />
              </React.Suspense>
            </Feature>
          );
        case 5:
        case 4:
          // unstable_Profiler
          class ProfilerChild extends React.Component {
            state = {count: 0};
            incrementCount = () =>
              this.setState(prevState => ({count: prevState.count + 1}));
            render() {
              return (
                <div>
                  count: {this.state.count} <button onClick={this.incrementCount}>increment</button>
                </div>
              );
            }
          }
          const onRender = (...args) => console.log('onRender()', ...args);
          const Profiler = React.unstable_Profiler || React.Profiler;
          apps.push(
            <Feature key="unstable_Profiler" label="unstable_Profiler" version="16.4+">
              <Profiler id="count" onRender={onRender}>
                <div>
                  <ProfilerChild/>
                </div>
              </Profiler>
            </Feature>
          );
        case 3:
          // createContext()
          const LocaleContext = React.createContext();
          LocaleContext.displayName = 'LocaleContext';
          const ThemeContext = React.createContext();
          apps.push(
            <Feature key="createContext" label="createContext" version="16.3+">
              <ThemeContext.Provider value="blue">
                <ThemeContext.Consumer>
                  {theme => (
                    <div>theme: {theme}</div>
                  )}
                </ThemeContext.Consumer>
              </ThemeContext.Provider>
              <LocaleContext.Provider value="en-US">
                <LocaleContext.Consumer>
                  {locale => (
                    <div>locale: {locale}</div>
                  )}
                </LocaleContext.Consumer>
              </LocaleContext.Provider>
            </Feature>
          );
  
          // forwardRef()
          const AnonymousFunction = React.forwardRef((props, ref) => (
            <div ref={ref}>{props.children}</div>
          ));
          const NamedFunction = React.forwardRef(function named(props, ref) {
            return (
              <div ref={ref}>{props.children}</div>
            );
          });
          const CustomName = React.forwardRef((props, ref) => (
            <div ref={ref}>{props.children}</div>
          ));
          CustomName.displayName = 'CustomNameForwardRef';
          apps.push(
            <Feature key="forwardRef" label="forwardRef" version="16.3+">
              <AnonymousFunction>AnonymousFunction</AnonymousFunction>
              <NamedFunction>NamedFunction</NamedFunction>
              <CustomName>CustomName</CustomName>
            </Feature>
          );
  
          // StrictMode
          class StrictModeChild extends React.Component {
            render() {
              return 'StrictModeChild';
            }
          }
          apps.push(
            <Feature key="StrictMode" label="StrictMode" version="16.3+">
              <React.StrictMode>
                <StrictModeChild/>
              </React.StrictMode>
            </Feature>
          );
  
          // unstable_AsyncMode (later renamed to unstable_ConcurrentMode, then ConcurrentMode)
          const ConcurrentMode = React.ConcurrentMode || React.unstable_ConcurrentMode || React.unstable_AsyncMode;
          apps.push(
            <Feature key="AsyncMode/ConcurrentMode" label="AsyncMode/ConcurrentMode" version="16.3+">
              <ConcurrentMode>
                <div>unstable_AsyncMode was added in 16.3, renamed to unstable_ConcurrentMode in 16.5, and then renamed to ConcurrentMode in 16.7</div>
              </ConcurrentMode>
            </Feature>
          );
        case 2:
  
          // Fragment
          apps.push(
            <Feature key="Fragment" label="Fragment" version="16.4+">
              <React.Fragment>
                <div>one</div>
                <div>two</div>
              </React.Fragment>
            </Feature>
          );
        case 1:
        case 0:
      }
      break;
    case 15:
      break;
    case 14:
      break;
  }
  
  // Simple stateful app shared by all React versions
  class SimpleApp extends React.Component {
    state = {count: 0};
    incrementCount = () => {
      const updaterFn = prevState => ({count: prevState.count + 1});
      trace(
        'Updating count',
        performance.now(),
        () => this.setState(updaterFn)
      );
    };
    render() {
      const {count} = this.state;
      return (
        <div>
          {count % 2 === 0 ? (
            <span>count: {count} <small>(even)</small></span>
          ) : (
            <span>count: {count}</span>
          )} <button onClick={this.incrementCount}>increment</button>
        </div>
      );
    }
  }
  apps.push(
    <Feature key="Simple stateful app" label="Simple stateful app" version="16.0">
      <SimpleApp />
    </Feature>
  );
  
  // This component, with the version prop, helps organize DevTools at a glance.
  function TopLevelWrapperForDevTools({ version }) {
    return (
      <div>
        <h1>React {version}</h1>
        {apps}
      </div>
    );
  }
  TopLevelWrapperForDevTools.displayName = 'React';
  
  ReactDOM.render(
    <TopLevelWrapperForDevTools version={React.version} />,
    document.getElementById('root')
  );
  