Repository navigation
v0.19.0
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.
defaultBackgroundColoris deprecated. It still works;preview.backgroundColorreplaces 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 thevue-routerfix.
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.tsxor.story.jsxfile. Each variant has arenderthat returns JSX.renderis a component body: it runs again on every state change, so hooks work inside it.initStategives a variant the state panel, andrenderreceives that state and asetStatethat merges what you pass, as a class component's does.setupReactruns before a story mounts, and itsaddWrapperputs 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
initStatesays why its panel is empty. - Requirements:
react@^19.0.0andreact-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 insideStrictMode; add it as a wrapper if you want its checks. - There is no
storyMatchto 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.tsxfiles, and whichever of the two plugins comes first inpluginstakes 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.1placeholder, with adeprecatedwarning as the only sign. Install with npm, or add--config.minimum-release-age=0to the pnpm line. - The React guide walks through all of it.
- What works: a story is a
-
A
previewconfig group sets what a story's preview opens at (#1109, #1152). Its keys mirror the preview toolbar:backgroundColor,responsiveWidth,responsiveHeight,rotate,checkerboardandtextDirection. 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.defaultBackgroundColoris deprecated and still honoured.preview.backgroundColorwins 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-solidand@poveste/plugin-reactnow add**/*.story.tsxand**/*.story.jsxthemselves. A Solid book no longer needs thestoryMatchline that 0.18.0 asked for, and you can delete it; leaving it in changes nothing. SettingstoryMatchyourself 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: returnstoryMatchfrom your plugin'sdefaultConfig().
🩹 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.vuebeside 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 whoseonDevEventhandler 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 yoursetupFileimports. A book's owncolor-schemewins 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-schemeis no longer overridden.
- What changes in a dark preview: text with no colour of its own was black and is now white. A native
-
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: falseon a single layout oriframeGrid: falseon 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 owntheme.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 withSyntaxError: 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,moduleorexportsat 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))andconst 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 asfileURLToPath, 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-svelteoffered 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 hasnodeanddefaultconditions, as@poveste/plugin-vuehas: 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 thenodecondition gets the helpers and noHstSvelte.
- Any framework: a module that declared
-
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 withvaporitself stayed on "Loading...". All three now render, with controls and generated source as for any other component. This was measured on3.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 devshowed 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 as3.6.0-rc.10or3.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 entryand the 25Module "node:https" has been externalizedwarnings of every build are gone. One kind is left: inpoveste dev, a Nuxt book still printsNUXT_E1005and 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
quasaronly when the first story loaded, then bundle it and reload the page.@poveste/plugin-quasarnow 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.assetsset insveltekit({ ... }), atheme.faviconin that directory failed the config with "seems to target a file that does not exist", because Poveste looked for it instatic/. This also corrects the 0.18.0 notes, which said a Kit 3 book's static files come fromstatic/whateverfiles.assetssays. 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 syncthat never finishes is stopped after 60 seconds (#1211, #1256). A Kit or Vite config that never settles used to blockpoveste dev,buildandpreviewwith nothing printed. Poveste now says the sync was stopped and carries on, as it does for a sync that fails. -
Svelte:
metaon<Hst.Story>and<Hst.Variant>is collected (#1206, #1260, #1259, #1296). Both were dropped, someta={{ storyOptions: false }}on a story left the options pane showing. In the same release, the type ofHst.Radio'soptionsaccepts 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 withHst(...).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
storyMatchnames stories that don't end in.story.svelte, editing a story kept component hot reload on and skipped the preview reload that a.story.sveltefile gets. Both now follow the story whereverstoryMatchfinds 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 readsiframeGrid. 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
excludePluginsmatches. -
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 previewtakes--config(#1302, #1310), asdevandbuilddo. It accepted the option silently and read the default config, so a book built with--configand its ownoutDirwas served as 404. -
@poveste/shared's types no longer importvue-router(#1199, #1255). The package neither depends on it nor peers it, so a project type-checking withskipLibCheck: falsefailed inside Poveste's declarations, and a Svelte, Solid or React project has no router installed at all.ClientCommandContext.routeis nowClientCommandRoute, a new exported type withpath,fullPath,hash,name,params,queryandmeta. This narrows a type: a plugin command that reads avue-router-only field offctx.route, such asmatchedorredirectedFrom, no longer type-checks. In a project withoutvue-routerthose 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/appshipped 13 and@poveste/plugin-vue10. 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-svelteand@poveste/plugin-vuebundle other packages' code. Each now carriesdist/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
storyMatchdoes 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
setupFilereference 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,setupSolidorsetupReact. A default export is loaded and never called, with no warning. ThesupportMatchtable gains its Solid and React rows. -
A story's
metaandmeta.storyOptionsare documented (#1261, #1298), in the Vue and Svelte story references:storyOptions: falsehides the options pane for one story, andtrueshows it, whatever the reader has set. Solid and React stories take nometayet (#1295). -
The Svelte examples page lists
Hst.ColorandHst.Date(#1317). It saidHst.Colordid 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 thesetupFileline in the config, names the filesrc/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@scopein 146, in December 2025, and Firefox ESR 140 does not have it. On a Firefox older than 146 a book needsisolateStyles: 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-colorsets nothing. The story pages saymetais yours to extend and show how a TypeScript book declares its keys, and the variant pages document a variant'smeta. -
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
previewconfig 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 previewthe --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:
- 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: