Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Documentation]: Svelte - Better documentation for decorators/render function #26896

Open
rChaoz opened this issue Apr 20, 2024 · 1 comment
Open

Comments

@rChaoz
Copy link

rChaoz commented Apr 20, 2024

Describe the problem

It's not very clear how to use decorators/the render function in Svelte correctly.

For example, the return value of a decorator function is a Story Result - but it's not quite clear how to use that in Svelte. In React, it's just some JSX, but in Svelte it's an object with 4 undocumented properties - Component and props (self-explaining), but also on and decorator (no idea what they do).
It is mentioned that you can choose what component to render and with what props:

return {
    Component: SomeComponent,
    props: { prop1: 1, prop2: 2 }
}

But nothing more than that. The section about custom render functions linked in a couple of pages is missing (choose Svelte and click on "Custom render function" in the table of contents on the right). I tried returning some component in the decorator property, which I realised exists because of TypeScript autocomplete, but it doesn't seem to do anything:

return {
    Component: SomeComponent,
    props: { prop1: 1, prop2: 2 },
    decorator: MyWrapper,
}

I would expect this to render this:

<MyWrapper>
    <SomeComponent {...props} />
</MyWrapper>

But the wrapper component is never actually instantiated. It also seems like you can actually use React hooks in decorators, even when using Svelte. By doing some more digging, this seems to work:

// preview.ts
import type { Preview } from "@storybook/svelte"
import { global } from "@storybook/global"
import { useEffect } from "@storybook/preview-api"

const preview: Preview = {
    decorators: [
        (Story) => {
            useEffect(() => {
                console.log("In effect", global.document.getElementById("storybook-root"))
            }, [])
            return Story()
        }
    ]
}

But this isn't really documented anywhere, The only time this is mentioned is in the "Writing addons" sections. But even there, global is not documented. Both are extremely useful for decorators.

Finally, in this PR it is stated you can set Svelte contexts, which is not stated anywhere in the docs. This is incredibly useful, as the only decorator example given in the docs is () => MarginDecorator, and it doesn't explain how one would set the margin size, for example, based on global arguments. This is actually possible to do (as described in the PR above) like so:

import { setContext } from 'svelte'

const decorator = () => {
    setContext('marginDecoratorSize', 12)
    return MarginDecorator
}

The MarginDecorator component can then do getContext('marginDecoratorSize').

Additional context

No response

@rChaoz rChaoz changed the title [Documentation]: Better documentation for decorators/render function (Svelte) [Documentation]: Svelte - Better documentation for decorators/render function Apr 20, 2024
@jonniebigodes jonniebigodes self-assigned this May 4, 2024
@JReinhold
Copy link
Contributor

Some additional context:

... in Svelte it's an object with 4 undocumented properties - Component and props (self-explaining), but also on and decorator (no idea what they do). It is mentioned that you can choose what component to render and with what props:

The decorator in the render-function is an internal construct, and using it when defining stories is not supposed to work - I believe you've figured this out. Using decorators as documented is the way to do it.

It also seems like you can actually use React hooks in decorators, even when using Svelte.

Yes this is a rather strange API choice, the hooks from @storybook/preview-api aren't actually React hooks at all, they just behave very similar and so the same names where chosen. That's why they are framework-agnostic.

But this isn't really documented anywhere, The only time this is mentioned is in the "Writing addons" sections.

We have a long backlog of API docs missing, and preview-api and manager-api are big omissions currently. I can understand why that is frustrating some times. In due time.

But even there, global is not documented. Both are extremely useful for decorators.

global from @storybook/global shouldn't be necessary at all. It's an old artifact that was needed eons ago before browsers and runtimes converged on globalThis. You should be able to do console.log("In effect", document.getElementById("storybook-root")) directly as you'd expect to, and omit the global altogether. We haven't yet confirmed if @storybook/global can be removed everywhere internally, which is why we haven't touched the docs on it yet too.

Finally, in this PR it is stated you can set Svelte contexts, which is not stated anywhere in the docs. This is incredibly useful, as the only decorator example given in the docs is () => MarginDecorator, and it doesn't explain how one would set the margin size, for example, based on global arguments. This is actually possible to do (as described in the PR above) like so:

import { setContext } from 'svelte'

const decorator = () => {
    setContext('marginDecoratorSize', 12)
    return MarginDecorator
}

The MarginDecorator component can then do getContext('marginDecoratorSize').

PRs welcome! If you can articulate this feature and it's usefulness in a meaningful way it would be great if you could submit a PR adding it to the docs!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

4 participants