Headless

Headless demo built with Expressive MVC - the complete source below runs as an editable sandbox when JavaScript is enabled.

App.tsx

import './App.css';

import Split from './common/Split';
import { Component } from '@expressive/react';

export default () => (
  <div className="container">
    <h1>Headless</h1>
    <p>
      A Component without <code>render()</code> draws nothing. Children pass
      through its context provider, which makes placement in the tree the entire
      feature: it owns a lifecycle and hosts the suspense and error boundaries
      for everything below it.
    </p>
    <Scopes />
    <small>Same Readout, same class, two scopes - each finds the Ticker above it.</small>
  </div>
);

const Scopes = () => (
  <Split>
    <Ticker rate={100}>
      <Readout />
    </Ticker>
    <Ticker rate={1000}>
      <Readout />
    </Ticker>
  </Split>
);

class Ticker extends Component {
  rate = 1000;
  elapsed = 0;

  get seconds() {
    return (this.elapsed / 1000).toFixed(1);
  }

  mount() {
    const started = Date.now();
    const timer = setInterval(() => {
      this.elapsed = Date.now() - started;
    }, this.rate);

    return () => clearInterval(timer);
  }
}

const Readout = () => {
  const { seconds, rate } = Ticker.get();

  return (
    <div className="readout">
      <strong>{seconds}s</strong>
      <small>every {rate}ms</small>
    </div>
  );
};

App.css

.readout {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  padding: var(--s4);
}

.readout strong {
  font-family: var(--font-mono);
  font-size: var(--t-2xl);
  color: var(--accent);
}