Skip to content

Releases: observablehq/framework

v1.13.2

23 Jan 16:35
@Fil Fil
82412a4
Compare
Choose a tag to compare

Bug fix

Full Changelog: v1.13.1...v1.13.2

v1.13.1

22 Jan 16:49
4da167e
Compare
Choose a tag to compare

Bug fixes

  • Fix import of npm:react-dom for React 19. #1866 #1872
  • Fix module hash when a referenced file’s modification time changes, but not its contents. #1836 #1837

Full Changelog: v1.13.0...v1.13.1

v1.13.0

13 Nov 15:55
8f5200d
Compare
Choose a tag to compare

New features

Bug fixes and other improvements

New Contributors

Full Changelog: v1.12.0...v1.13.0

v1.12.0

01 Oct 17:14
ab7d7f3
Compare
Choose a tag to compare

New features

Bug fixes and other improvements

Full Changelog: v1.11.0...v1.12.0

v1.11.0

03 Sep 16:04
10cd987
Compare
Choose a tag to compare

New features

Bug fixes and other improvements

  • The build command now empties the output root before building. #1568
  • The convert command now outputs to the source root by default. #1579
  • Fix rendering of command-line select prompts with many choices. #1618
  • Inputs.file now supports the file.href property. #1608
  • Pages now include a <meta name="generator"> tag. #1609
  • Use CREATE TABLE for small Parquet files with DuckDBClient.of. #1617
  • Fix building when SQL front matter refers to a remote file. #1635 #1636

New examples and documentation

New contributors

Full Changelog: v1.10.1...v1.11.0

v1.10.1

09 Aug 17:16
a3f5750
Compare
Choose a tag to compare

New features

Bug fixes and other improvements

  • Fix crash attempting to preserve expanded state. #1559 #1561
  • Fix content hashes of global imports in _observablehq, _npm, and more. #1555 #1557
  • Optimize resize to ignore height changes for unary render functions. #1563 #1564
  • Improve slugify algorithm used for Markdown header anchors. #1552 #1562

Full Changelog: v1.10.0...v1.10.1

v1.10.0

06 Aug 22:19
c5d57f7
Compare
Choose a tag to compare

New features

  • Add FileAttachment.arquero for loading an Arrow, Parquet, CSV, TSV, or JSON file as an Arquero table. #1509
  • Inputs.table now supports the select option to suppress user selection (checkboxes). #1541
  • In narrow windows, you can now close the floating sidebar with Escape. #1526
  • The inspector now preserves the deep expanded state for dynamic values. #1458 #1475

Bug fixes and other improvements

  • Fix a bug where expanded inspected values would not be cleaned up on invalidation. #1456 #1457
  • Fix a crash when expanding inspected values while certain text is selected. #1475
  • Fix a spurious error when using Control-C to terminate the preview server. #1459 #1460
  • Fix modulepreload for local components during preview. #1537
  • Optimize imports of npm:react-dom. #1467
  • Tweak format of project identifiers in prompts during deploy. #1451
  • Fix spinner rendering when not in a TTY. #1446 #1447 #1473

New examples

New showcase examples:

New technique examples:

New contributors

Full Changelog: v1.9.0...v1.10.0

v1.9.0

12 Jun 16:21
0f2c92e
Compare
Choose a tag to compare

JSX + React ⚛

Framework now supports JSX rendered with React, 🎉 providing a powerful new mechanism for implementing reusable stateful components. You can both write fenced code blocks (```jsx) and import JSX modules (.jsx). For example, to define a Greeting component that accepts a subject prop:

function Greeting({subject}) {
  return <div>Hello, <b>{subject}</b>!</div>
}

You can then call the built-in display function to render JSX content:

display(<Greeting subject="JSX" />);

The display function in JSX code blocks uses React’s createRoot to render the specified contents into the DOM. When you call display again later, it applies React’s reconciliation algorithm to efficiently update the DOM.

Naturally, you can also use React’s built-in hooks such as useState, useEffect, and useRef. For example, here is a Counter component whose count you can increment by clicking a button:

function Counter() {
  const [count, setCount] = React.useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      You clicked {count} times
    </button>
  );
}

React and ReactDOM are now available by default in Markdown; if you prefer, you can also import them explicitly from npm:react or npm:react-dom.

Span-less inline expression rendering

Framework’s inline expressions allow you to interpolate dynamic content anywhere on the page using ${…}. Previously, interpolated content was wrapped in a SPAN element; now Framework uses a comment (e.g., <!--:85902a01:-->) to track where to insert displayed content. This enables a variety of new use cases. For example, you can now use inline expressions to populate the contents of a grid,

<div class="grid grid-cols-4">
  ${d3.range(4).map((i) => html`<div class="card">Hello ${i}</div>`)}
</div>

… or to generate table rows,

<table>
  <thead><th>Index</th></thead>
  <tbody>${d3.range(4).map((i) => html`<tr><td>${i}</td></tr>`)}</tbody>
</table>

… or even within SVG elements!

<svg width="640" height="120">
  <text x="20" y="20">My favorite number is ${Math.random()}</text>
</svg>

As part of this change, we also fixed several edge cases in incremental updates during preview. (Previously we only tracked changes to top-level elements, but now we also track changes to top-level text nodes and comments.)

More robust inline expression parsing

We’ve also improved how we parse inline expressions: Framework now uses the HTML5 tokenizer algorithm (adopted from Hypertext Literal) to determine context, allowing Framework to ignore inline expressions in unsupported contexts such as attributes, coments, and raw text. This means that if you comment out a chunk of Markdown that includes an inline expression, Framework no longer runs the code (and no longer generates an error)!

<!-- ${"this code doesn’t run"} -->

In the future, we’d like to support interpolation into attributes <a href=${link}> and possibly raw text <textarea>${1 + 2}</textarea>; please upvote #32 if you’re interested in this feature.

Framework now also uses Acorn’s tokenizer to determine when an inline expression ends. Previously, Framework counted quotes and curly braces; by adopting Acorn’s tokenizer, Framework can correctly parse (and skip) JavaScript comments within inline expressions. For example, the following inline expression evaluates to 3:

${1 + /* } */ 2}

Lastly, Framework now correctly handles backslash escaping of inline expressions within HTML blocks. To escape an inline expression, resulting in the literal text ${1 + 2}, place a backslash \ before either the dollar sign $ or left curly brace {:

<pre>\${1 + 2}</pre>

To instead show a literal backslash prior to the result of the inline expression \3, use two backslashes \\:

<pre>\\${1 + 2}</pre>

Or, to show a literal backslash followed by literal text \${1 + 2}, use three backslashes:

<pre>\\\${1 + 2}</pre>

Together, these rendering and parsing improvements make Framework’s inline expressions feel more robust — they just work.

Other improvements

The FileAttachment function now returns a canonical instance: calling FileAttachment with the same name will return the same object, allowing easier comparison.

FileAttachment("foo.csv") === FileAttachment("foo.csv") // true

The Mod-Enter keyboard shortcut now opens search results in a new tab, making it easier to open multiple search results for the same query.

Sample datasets, such as penguins and miserables, are now self-hosted from npm:@observablehq/sample-datasets, allowing you to work with sample data while offline.

The deploy command now supports the --deploy-config command-line argument to specify an alternative path to the deploy.json configuration file. (By default, this file lives in .observablehq/deploy.json within the source root.) The deploy command now prints a better error message when attempting to deploy without authentication from a non-interactive terminal.

Examples improvements

We’ve added a variety of new technique examples:

The examples are now searchable from the Framework documentation. The example config files have also been greatly simplified by removing shared boilerplate. Lastly, descenders in the hero text of the default template’s home page are no longer clipped.

Thanks @martinswan for contributing to the docs!

Full Changelog: v1.8.0...v1.9.0

v1.8.0

25 May 00:01
5838c5a
Compare
Choose a tag to compare

Sidebar and pager improvements

Sidebar sections can now have header links, which is useful for sections with main pages. Clicking on the section will visit the section’s main page while opening the section in the sidebar to show related pages. To give a section a header link, set the path option for a given section. See the pages config option for more.

Screenshot 2024-05-22 at 6 16 47 PM
export default {
  pages: [
    {
      name: "Section 1",
      path: "/s01/",
      open: false,
      pages: [
        {name: "Page 1.1", path: "/s01/page1"}
      ]
    },
    {
      name: "Section 2",
      path: "/s02/",
      open: false,
      pages: [
        {name: "Page 2.1", path: "/s02/page1"},
        {name: "Page 2.2", path: "/s02/page2"}
      ]
    }
  ]
};

The sidebar now supports links to external pages, which automatically open in a new window. (We use this feature in the Framework docs to link to examples.) The sidebar now renders sections correctly when there are no top-level pages.

Sidebar pages and sections can now use the pager option to define separate sequences for the next & previous links in the footer, or to opt-out of the pager for specific pages or sections. (We use this feature in the Framework docs to have separate sequences for inputs, and to suppress the pager on library pages.) The pager option can also be defined in a page’s front matter. If a page sets the pager front matter option to false or null, the pager is hidden.

Other improvements

The head, header, and footer config options can now be specified as functions, allowing dynamic footers. These functions are passed an object with the page’s title, (front-matter) data, and path, and must return a string.

We’ve improved how data loaders are spawned, fixing a FATAL Error: fsync failed! error with DuckDB data loaders that output directly to stdout. We also fixed the normalization of plain HTML links such as <a href="/test.html">hello</a>; these are now correctly converted to relative links.

New examples! 🎉

We’ve been hard at work developing new examples.

See all examples here: https://github.com/observablehq/framework/tree/main/examples

Please let us know which examples you’d like to see.

Full Changelog: v1.7.1...v1.8.0

v1.7.1

14 May 01:23
1a62107
Compare
Choose a tag to compare

Page stats

The build command now outputs summary page size statistics, including the weight of imported JavaScript modules and referenced files such as data. This helps you keep an eye on performance, encouraging you to reduce bloat by removing unnecessary imports or by optimizing data loaders to produce smaller files.

Screenshot 2024-05-01 at 1 06 53 PM

Bug fixes

Prevent the sidebar from closing on narrow windows when the search input is focused via Command-K and then a link is clicked. Avoid a rendering glitch in Safari with animated loading indicators ↻. Downgrade JSDOM to ^23.2.0 to avoid a regression (not a valid selector error) in the selectors implementation. Automatically link H1, H2, H3, and H4 elements that have an id attribute, enabling them to also appear in the table of contents. Fix table of contents highlighting when the heading id contains non-ASCII characters.

Watch changes to static assets during preview, such as referenced stylesheets and images, so that changes to these files update automatically. Also populate FileAttachment.lastModified on update during preview.

When deploying to Observable, correctly update titles when linking to existing projects.

And more…

The resize function now implicitly awaits promises returned by the render function; the render function can also now return null to clear the container. Deprecate the scripts config option.

Full Changelog: v1.7.0...v1.7.1