Framework
1.12.0 GitHub️ 2.4k

Observable Generators

The Observable standard library includes several generator utilities. These are available by default in Markdown as Generators, but you can import them explicitly:

import {Generators} from "observablehq:stdlib";

input(element)

Source · Returns an async generator that yields whenever the given element emits an input event, with the given element’s current value. (It’s a bit fancier than that because we special-case a few element types.) The built-in view function uses this.

const nameInput = display(document.createElement("input"));
const name = Generators.input(nameInput);
name

observe(initialize)

Source · Returns an async generator that immediately invokes the specified initialize function, being passed a change callback function, and yields the passed value whenever change is called. The initialize function may optionally return a dispose function that will be called when the generator is terminated.

const hash = Generators.observe((change) => {
  const changed = () => change(location.hash);
  addEventListener("hashchange", changed);
  changed();
  return () => removeEventListener("hashchange", changed);
});
hash

queue(change)

Source · Returns an async generator that immediately invokes the specified initialize function, being passed a change callback function, and yields the passed value whenever change is called. The initialize function may optionally return a dispose function that will be called when the generator is terminated.

This is identical to Generators.observe except that if change is called multiple times before the consumer has a chance to process the yielded result, values will not be dropped; use this if you require that the consumer not miss a yielded value.

const hash = Generators.queue((change) => {
  const changed = () => change(location.hash);
  addEventListener("hashchange", changed);
  changed();
  return () => removeEventListener("hashchange", changed);
});
hash

now()

Source · Returns a generator that repeatedly yields Date.now(), forever. This generator is available by default as now in Markdown.

const now = Generators.now();
now

width(element)

Source · Returns an async generator that yields the width of the given target element. Using a ResizeObserver, the generator will yield whenever the width of the element changes. This generator for the main element is available by default as width in Markdown.

const width = Generators.width(document.querySelector("main"));
width

dark()

Source · Returns an async generator that yields a boolean indicating whether the page is currently displayed with a dark color scheme.

const dark = Generators.dark();

If the page supports both light and dark mode (as with the default theme), the value reflects the user’s preferred color scheme. The generator will yield a new value if the preferred color changes — as when the user changes their system settings, or if the user’s system adapts automatically to the diurnal cycle — allowing you to update the display as needed without requiring a page reload.

If the page only supports light mode, the value is always false; likewise it is always true if the page only has a dark theme.

The current theme is: .

The current theme is: *${dark ? "dark" : "light"}*.

This generator is available by default as dark in Markdown. It can be used to pick a color scheme for a chart, or an appropriate mix-blend-mode:

Plot.plot({
  height: 260,
  color: {scheme: dark ? "turbo" : "ylgnbu"},
  marks: [
    Plot.rectY(
      olympians,
      Plot.binX(
        {y2: "count"},
        {
          x: "weight",
          fill: "weight",
          z: "sex",
          mixBlendMode: dark ? "screen" : "multiply"
        }
      )
    ),
    Plot.ruleY([0])
  ]
})