Skip to content

autoPropsDisabled is silently dead for Svelte and vanilla, and only the docs say so #460

Description

@50rayn

autoPropsDisabled is accepted by Svelte and vanilla stories and does nothing. #459 made the reference pages say so; nothing tells the person who already wrote the prop and is looking at an empty controls panel.

A warning is the right answer. I built one in an earlier revision of #459 and removed it, because a max-effort review found it broken in five separate ways. This issue exists so the second attempt starts from what that cost, rather than rediscovering it.

Build it at the app layer, not per plugin

The first version lived in packages/poveste-plugin-svelte/src/client/MountVariant.svelte. That was the wrong altitude, and it is why most of the defects below exist.

packages/poveste-app/src/app/util/mapping.ts:9 already copies autoPropsDisabled for every framework, and mapFile receives file.supportPluginId — the app switches on it at GenericRenderStory.vue:19, StorySourceCode.vue:21 and util/docs.ts:16. One check there — prop set, plugin is not Vue — covers Svelte, vanilla, and the React and Solid plugins in #371 and #61 without any of them writing a line.

What the leaf-component version got wrong

It never fired for the shape the docs document. MountStory.svelte:20 forwards $$restProps only in the variants.length === 1 && variants[0].id === '_default' branch; the {:else} renders a bare <slot /> and drops story-level props. So <Hst.Story autoPropsDisabled> over explicit <Hst.Variant> children — the shape most conformance stories use — warned nowhere. Verified in a browser against a built preview: console empty.

A config default would have warned on stories nobody wrote the prop on. autoPropsDisabled is not in omitInheritStoryProps, and poveste/src/node/collect/index.ts:138 merges defaultStoryProps onto the story object with ??=. A mixed Vue+Svelte book setting defaultStoryProps: { autoPropsDisabled: true } for its Vue stories would get the warning on every Svelte story, blaming the author for a line in poveste.config.ts that the warning's own advice cannot address. Any implementation has to distinguish an explicitly-written prop from a config-inherited one, or say which it is.

Dedupe is harder than it looks. A plain {} keyed by variant.id is wrong twice: prototype names (constructor, toString, __proto__) read truthy on the first check and suppress the warning forever, and variant.id is only story-scoped, so two stories reusing id="default" — which docs/reference/svelte/variant.md recommends — may collide. RenderStory.svelte:35 and RenderVariant.svelte:32 already solve this with a flag on the variant object (__pvtStateWarned); prefer that idiom over inventing a third.

The realms are not what they look like. mount.ts:75 always sets __pvtTargetVariantId to a store, so the ?? null in MountVariant.svelte never yields null — gating on "the app realm" suppresses the warning entirely. The duplicate line people see is the app realm plus one sandbox, not two sandboxes; in grid layout it is 2N. Whatever emits the warning has to decide deliberately how many realms speak.

It shipped with no test. Deleting the warning left lint, test, test:scripts and the whole Playwright suite green. examples/svelte5/playwright/state-sync.spec.ts:62 already does page.on('console', …) filtered on [poveste] for the sibling initState diagnostic and is the model to copy — note it matches console.error while this one is a console.warn.

The empty controls panel

StoryControls.vue:75 renders "No controls available for this story" for every framework. #459 tried adding "Add a controls slot, or return state from initState" and reverted it: vanilla has neither name — its API is onMountControls and a MountApi.state mutated in onMount — and for Vue the named pair is the documented secondary path while auto-props, the primary one, goes unmentioned. The panel has supportPluginId in scope, so per-framework advice is available; it is a small piece of the same job and belongs with it.

A guard, if one is worth building

#459 also carried scripts/check-auto-props.ts, asserting that the set of files writing _hPropDefs matched what the docs claim. It was removed. Two reasons it did not work, both worth avoiding:

Its regex only recognised the object-literal key form — state._hPropDefs = defs, bracket assignment and shorthand all slipped through, while a plain type declaration { _hPropDefs: PropDefinition[] } was a false positive. It failed open on the exact event it existed to catch.

And its failure message said "add the file to PRODUCERS", with nothing checking the docs half it also demanded. The documented remedy turned the check off.

If drift between the pages and the code is worth guarding, the repo already has a better-shaped mechanism: e2e/stories.ts SHARED_STORIES and e2e/controls.spec.ts drive the same conformance story across all four books. A story whose component has real props, asserting the Svelte book shows the empty controls state, fires on any second implementation regardless of how it is written, and survives renames and rewordings.

Not this issue

Real Svelte controls — Poveste owning the mounting so it owns the props — is #233, which stays open.

Related: #233, #371, #61, #459.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a:appThe book UI — chrome, sandbox, controls panea:pluginsPlugin API and official pluginsa:svelteSvelte plugin, SvelteKit, Hst surfacesprint:4-bugsIndependent correctness bugs; runs in parallel with any sprint

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions