Skip to content

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 10:17
· 127 commits to main since this release
c8eb3da

compare changes

Write stories for React 19 components, renderer only, and set in your config what a story's preview opens at.

It is a minor: the React plugin, the preview config group and plugin-added story patterns are new features. Nothing is renamed or removed and no version floor moved, and a Vue, Nuxt, Svelte, SvelteKit, Quasar or Solid book keeps its stories with no config change. Four things to know before you upgrade:

  • A dark preview looks different, and it is the most visible change in this release. Text with no colour of its own turns from black to white, and native widgets turn dark. A component with a light background and no text colour of its own becomes unreadable there. One line of CSS keeps the 0.18 behaviour. See the second fix.
  • defaultBackgroundColor is deprecated. It still works; preview.backgroundColor replaces it.
  • @poveste/plugin-svelte's export map changed. Node still resolves the plugin, and a browser now resolves the setup helpers only. See the Svelte setup-file fix.
  • One published type is narrower: ClientCommandContext.route, for plugin authors who type-check a command. See the vue-router fix.

Installing Nuxt with npm 10 fails at the moment, with or without Poveste. npm 10 is the version Node 22 ships with. Since Vite's devtools packages were released on 14 October, npm install in a Nuxt project stops with Cannot read properties of null (reading 'edgesOut'). It is an npm bug (npm/cli#9787), and npm 11.6 and later install the same packages: run npm install -g npm@latest, or npx npm@latest install.

🚀 Enhancements

  • Write stories for React components with @poveste/plugin-react, renderer only for now (#371, #1136, #1137, #1138, #1272).

    • What works: a story is a .story.tsx or .story.jsx file. Each variant has a render that returns JSX. render is a component body: it runs again on every state change, so hooks work inside it. initState gives a variant the state panel, and render receives that state and a setState that merges what you pass, as a class component's does. setupReact runs before a story mounts, and its addWrapper puts a component around it. The source panel shows the story file.
    • Not here yet: controls built from your components, and generated per-variant source. A variant without initState says why its panel is empty.
    • Requirements: react@^19.0.0 and react-dom@^19.0.0, and a JSX transform in your Vite config, such as @vitejs/plugin-react. React 18 is not supported. A story is not rendered inside StrictMode; add it as a wrapper if you want its checks.
    • There is no storyMatch to set. The plugin adds its own patterns to the defaults.
    • React and Vue stories can share a book. React and Solid stories cannot yet (#1273): both are .story.tsx files, and whichever of the two plugins comes first in plugins takes them all.
    • Installing with pnpm in the first day: pnpm's release-age cooldown holds back a version published less than a day ago. For a package that is new in this release, what it installs instead is the empty 0.0.1 placeholder, with a deprecated warning as the only sign. Install with npm, or add --config.minimum-release-age=0 to the pnpm line.
    • The React guide walks through all of it.
  • A preview config group sets what a story's preview opens at (#1109, #1152). Its keys mirror the preview toolbar: backgroundColor, responsiveWidth, responsiveHeight, rotate, checkerboard and textDirection. Until now a book could set only the background, so every story opened 720 pixels wide, a width that matches none of the default presets. Each value applies on every load until the reader changes that setting in the toolbar. From then on their choice wins for that setting, and the others keep following your config. defaultBackgroundColor is deprecated and still honoured. preview.backgroundColor wins when a book sets both. The config reference lists each key and its default.

  • A framework plugin can add its story patterns to the defaults (#1124, #1157). @poveste/plugin-solid and @poveste/plugin-react now add **/*.story.tsx and **/*.story.jsx themselves. A Solid book no longer needs the storyMatch line that 0.18.0 asked for, and you can delete it; leaving it in changes nothing. Setting storyMatch yourself still replaces the whole list, plugin patterns included. So in a book with two frameworks, either leave the key out or name every kind of story in it. For plugin authors: return storyMatch from your plugin's defaultConfig().

🩹 Fixes

  • In a Vue book's poveste dev, "generate story" works (#1064, #1170, #1176, #1174, #1184). The component picker listed nothing. It now lists your components, writes <Component>.story.vue beside the component you pick, and the new story appears in the sidebar. This is the fix that was pulled from 0.18.0, together with fixes for the two ways it could stop the dev server. A plugin whose onDevEvent handler throws is now logged under the plugin's name and skipped. A story that can't be written, because the file already exists for instance, is logged and no story is opened.

  • The browser is told each preview's colour scheme (#991, #1167, #1171). Until now a preview only got a class for your CSS to read, and the browser itself was told nothing, so it drew everything of its own light. Now form controls, scrollbars and default text follow the preview's setting. A preview is dark when the reader picks dark in the toolbar, or when the setting is auto, which is the default, and their system is dark.

    • What changes in a dark preview: text with no colour of its own was black and is now white. A native <input> was white with black text and is now dark with white text. Plain text straight on the dark preview background was black on dark, and is now readable.
    • What gets worse: a component with a hard-coded light background and no text colour of its own. It was black on white, and is now white on white.
    • To keep the 0.18 behaviour, add :root { color-scheme: light; } to the CSS file your setupFile imports. A book's own color-scheme wins over Poveste's, and with that rule the text, the card and the input measure exactly as they did on 0.18.3. Giving the component a text colour fixes it too, and that is what makes it readable on any dark page.
    • theme.defaultColorScheme: 'light' is not the same thing. It changes what a new reader starts on and takes away the book's dark default. A reader who has opened the book before, or who picks Dark, still gets the dark preview.
    • A story rendered without an iframe takes its text colour from Poveste's interface, on 0.18 and now. There only the native widgets change.
    • Light previews are unchanged, and so is a book that already sets its own text colour.
    • A screenshot baseline taken with a dark preview will change once. One taken light will not.
    • This is the other fix pulled from 0.18.0. It comes back with both of its defects fixed: the preview's background preset shows through as before, and a book's own color-scheme is no longer overridden.
  • A story's dark-keyed CSS applies where Poveste renders the story itself (#332, #1312). In a story rendered without an iframe, which is iframe: false on a single layout or iframeGrid: false on a grid, a rule such as .dark .card { … } matched nothing, in dev and in a built book. So the story kept its light look in a dark preview. It now matches, with the default dark class or your own theme.darkClass. A screenshot baseline of such a story taken in a dark preview will change. Two other shapes of book CSS reach such a story's root where they did not, as they already do in an iframe: .dark { … } with the class itself as the subject, and :root > * { … }.

  • Svelte: a setup file that follows the guide builds and renders (#1301, #1309). With import { defineSetupSvelte } from '@poveste/plugin-svelte' in the setup file, as the Svelte guide writes it, every story failed to collect with SyntaxError: Identifier '__dirname' has already been declared. It has failed this way since 0.15.0, and on 0.14.0 the same import failed the build with a different error. There were two causes, and both are fixed:

    • Any framework: a module that declared __dirname, __filename, require, module or exports at its top level failed collection for the whole book, whether the module was yours or a dependency's. const __dirname = dirname(fileURLToPath(import.meta.url)) and const require = createRequire(import.meta.url) are the usual ways to meet it. A module that only reads those names gets the values it got before. One thing to know if you had that error: a module that uses Node-only APIs, such as fileURLToPath, still can't run in the page. It used to stop the build with this error. It now collects, the build passes, and the failure shows in the browser instead (#1323).
    • @poveste/plugin-svelte offered a browser its Node entry. A setup file also runs in the page, so the page loaded the Node plugin and Vite with it. The package's main export now has node and default conditions, as @poveste/plugin-vue has: Node resolves the plugin, and a page resolves the helpers only. This changes a published export map. A Vite or Poveste config is unaffected, because Node still resolves the plugin. A tool that resolves the package without the node condition gets the helpers and no HstSvelte.
  • A page opened just as a collection finishes keeps its story list up to date (#1218, #1258). In poveste dev, such a page could load two copies of the story list and apply every later update to the copy nothing was reading. The sidebar then missed each new, renamed or deleted story until the page was reloaded.

  • Vue 3.6 Vapor components work in stories (#1153, #1112, #1164, #1158, #1162, #1165). Under Vue 3.6, a story that imported a <script setup vapor> component failed to collect, so it was missing from the book. Once collected, it threw when it mounted. A story file written with vapor itself stayed on "Loading...". All three now render, with controls and generated source as for any other component. This was measured on 3.6.0-rc.10; Vue 3.6 has no stable release yet.

  • A project on a Vue prerelease shows its stories (#1163, #1180). On any Vue prerelease, poveste dev showed the sidebar and no story, because Poveste's interface and its stores ended up on two copies of Vue. The interface now shares the project's Vue when that is a prerelease above the supported floor, such as 3.6.0-rc.10 or 3.5.27-beta.1.

  • Nuxt: a working book prints fewer lines that read as errors (#1203, #1262). [NUXT_B7005] No client entry was found, Could not resolve client entry and the 25 Module "node:https" has been externalized warnings of every build are gone. One kind is left: in poveste dev, a Nuxt book still prints NUXT_E1005 and Vue warnings when a page mounts (#1283). 0.18.3 prints the same lines, and the book works.

  • Quasar: the first story loads without a second dependency pass (#1278, #1277). In a newly set-up Quasar book, Vite could find quasar only when the first story loaded, then bundle it and reload the page. @poveste/plugin-quasar now names it up front. This was measured in the project the Quasar starter generates; a book that already bundled Quasar in one pass sees no change.

  • SvelteKit 3: a favicon in a custom assets directory no longer stops the book (#1212, #1257). With files.assets set in sveltekit({ ... }), a theme.favicon in that directory failed the config with "seems to target a file that does not exist", because Poveste looked for it in static/. This also corrects the 0.18.0 notes, which said a Kit 3 book's static files come from static/ whatever files.assets says. Measured, that was wrong: the book already served and copied the directory Kit names. Only the favicon check used the wrong one.

  • SvelteKit: a svelte-kit sync that never finishes is stopped after 60 seconds (#1211, #1256). A Kit or Vite config that never settles used to block poveste dev, build and preview with nothing printed. Poveste now says the sync was stopped and carries on, as it does for a sync that fails.

  • Svelte: meta on <Hst.Story> and <Hst.Variant> is collected (#1206, #1260, #1259, #1296). Both were dropped, so meta={{ storyOptions: false }} on a story left the options pane showing. In the same release, the type of Hst.Radio's options accepts a map of value to label, in Vue and in Svelte, which the control already handled.

  • Svelte: a builtin control in a story's default slot no longer stops the build (#925, #1303). A control such as <Hst.Select> placed directly inside <Hst.Story>, outside any variant, failed collection with Hst(...).Select is not a function, and one such story failed the whole book.

  • Svelte: a story is recognised by what it renders, not by its file name (#474, #1306). In a book whose storyMatch names stories that don't end in .story.svelte, editing a story kept component hot reload on and skipped the preview reload that a .story.svelte file gets. Both now follow the story wherever storyMatch finds it.

  • A layout key that the layout's type doesn't read now warns (#333, #1304). { type: 'grid', iframe: false } built without a word and still got iframes, because a grid reads iframeGrid. Collection now prints the file, the key and the key to use. A valid layout prints nothing.

  • Nuxt: a plugin that throws in a story is named by its file (#1063, #1305). An unnamed plugin, which is the form Nuxt's docs teach first, left a gap where its name belongs in Poveste's warning. The warning now gives its path from the project root, which is also what excludePlugins matches.

  • A builtin control in a story draws its icon without the network (#255, #1313). Each story preview fetched Poveste's own icons, such as the chevron of a select, from the Iconify API, and showed none offline. The preview now carries the icon data the interface already ships. Icons that your own stories name are still fetched; that part of #255 is open.

  • poveste preview takes --config (#1302, #1310), as dev and build do. It accepted the option silently and read the default config, so a book built with --config and its own outDir was served as 404.

  • @poveste/shared's types no longer import vue-router (#1199, #1255). The package neither depends on it nor peers it, so a project type-checking with skipLibCheck: false failed inside Poveste's declarations, and a Svelte, Solid or React project has no router installed at all. ClientCommandContext.route is now ClientCommandRoute, a new exported type with path, fullPath, hash, name, params, query and meta. This narrows a type: a plugin command that reads a vue-router-only field off ctx.route, such as matched or redirectedFrom, no longer type-checks. In a project without vue-router those reads compiled only because the type could not be resolved, so nothing checked them. The value at runtime is unchanged.

  • Test files are no longer published (#1189, #1192). @poveste/app shipped 13 and @poveste/plugin-vue 10. The release gate now refuses a tarball that carries one.

  • Bundled third-party code ships its notices (#936, #1214). @poveste/app, @poveste/controls, @poveste/plugin-svelte and @poveste/plugin-vue bundle other packages' code. Each now carries dist/THIRD_PARTY_NOTICES.md, with every bundled package's name, version and licence text, and the build fails on a licence outside the allowed list.

📖 Documentation

  • More than one framework in a book (#1204, #1268, #1287). What to install, what goes in each config, how one setup file serves both frameworks, and what storyMatch does to a mixed book. Every statement in it was measured on a book installed from the packed packages.

  • React is named, as renderer only, wherever Poveste lists its frameworks (#1270, #1284, #1274, #1286): the README, the npm page, the home page, the supported-versions table and llms.txt. "Coming from Storybook" said there was no React or Solid plugin and sent React users elsewhere. It now names both as renderers and lists what they lack.

  • The setupFile reference says what the file has to export (#1285, #1287). It said "a default function". Poveste calls the function your framework's plugin reads: setupVue, setupSvelte, setupSolid or setupReact. A default export is loaded and never called, with no warning. The supportMatch table gains its Solid and React rows.

  • A story's meta and meta.storyOptions are documented (#1261, #1298), in the Vue and Svelte story references: storyOptions: false hides the options pane for one story, and true shows it, whatever the reader has set. Solid and React stories take no meta yet (#1295).

  • The Svelte examples page lists Hst.Color and Hst.Date (#1317). It said Hst.Color did not exist.

  • The Svelte setup page's snippets build as printed (#1321, #1322). The setup snippet imported ./poveste.css, a file the page never told you to create, so a book set up from it failed to build with an error that named a story. The page now shows the setupFile line in the config, names the file src/poveste.setup.ts, and says the stylesheet is yours to import. The config guide had the same import and is corrected.

  • The CSS guide names Firefox 146 for @scope, where it said 128 (#1321, #1322). Firefox shipped @scope in 146, in December 2025, and Firefox ESR 140 does not have it. On a Firefox older than 146 a book needs isolateStyles: false, as the guide already says of any browser without @scope.

  • Smaller corrections in the story and variant references (#1321, #1322). The Svelte pages write iconColor, which is the prop; icon-color sets nothing. The story pages say meta is yours to extend and show how a TypeScript book declares its keys, and the variant pages document a variant's meta.

  • The Nuxt guide says where story files go (#1203, #1262): anywhere under the project root, and how to keep stories under app/components/ out of Nuxt's auto-imported components.


   🚀 Features

  • app: Add a preview config group for what the story preview opens at  -  by @50rayn in #1152 (23422)
  • node: Let a framework plugin add its story globs to the defaults  -  by @50rayn in #1157 (5db57)
  • react: Add @poveste/plugin-react, a renderer for React stories  -  by @50rayn in #1136 (698b4)

   🐞 Bug Fixes

  • app:
    • Tell the browser each preview's colour scheme, without overriding a book's own  -  by @50rayn in #1171 (28579)
    • Let a story's dark-keyed CSS match where the app renders the story itself  -  by @50rayn in #1312 (8df77)
    • Draw a builtin control's icon in a story without asking the network for it  -  by @50rayn in #1313 (6ba52)
  • node:
    • Keep poveste dev up when a plugin's dev-event handler throws  -  by @50rayn in #1174 (8e5dd)
    • Keep poveste dev up when generating a story fails  -  by @50rayn in #1184 (efe42)
    • Collapse the chrome's Vue onto a project on a Vue prerelease  -  by @50rayn in #1180 (f43c2)
    • Keep a page's story list updating when it holds two copies of it  -  by @50rayn in #1258 (a9f54)
    • Keep two helpers that only specs import off the public entries  -  by @50rayn in #1293 (dd4bf)
    • Warn when a story's layout carries a key its type does not read  -  by @50rayn in #1304 (1cdb3)
    • Give poveste preview the --config option that dev and build have  -  by @50rayn in #1310 (94b78)
    • Build and render a book whose setup file follows the Svelte guide  -  by @50rayn in #1309 (4e2ed)
  • nuxt:
  • quasar:
  • react:
    • Add the React story globs to the defaults, so a book needs no storyMatch  -  by @50rayn in #1272 (dc062)
  • repo:
    • Stop publishing test files, and refuse them in the tarball check  -  by @50rayn in #1192 (1696d)
    • Record the package's own Node range in a dependency-engines exemption  -  by @50rayn in #1254 (7abec)
    • List reverts in the release body, and warn when the notes skip one  -  by @50rayn in #1265 (54355)
    • Let the commit hook accept the documented e2e scope  -  by @50rayn in #1311 (aba6b)
    • Say what stopped the plugin-list check reading the smoke script's array  -  by @50rayn in #1315 (b11b3)
    • Leave another library's re-exported symbols out of the doc-coverage figure  -  by @50rayn in #1316 (1c1a3)
  • shared:
  • svelte:
    • Stop a svelte-kit sync that never finishes, and say so  -  by @50rayn in #1256 (d6dc0)
    • Leave a SvelteKit 3 book's assets directory to SvelteKit  -  by @50rayn in #1257 (22bc3)
    • Collect a story's meta, and type-check the Svelte books in CI again  -  by @50rayn in #1259 (60561)
    • Collect a variant's meta, which a Svelte book dropped  -  by @50rayn in #1296 (62693)
    • Collect a story that has a builtin control in its default slot  -  by @50rayn in #1303 (19f2c)
    • Turn story-component HMR off by what a file renders, not by its name  -  by @50rayn in #1306 (047b7)
  • vue:
    View changes on GitHub