-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
addon-storysource not producing useful code examples using recommended stories approach #12495
Comments
Ok, this may turn into a self resolving issue, but I'll keep my notes for others having same quandary :) I'm starting to learn more digging deeper into the docs section and considering MDX and other alternatives per your writing docs guides: So, it looks for React this approach can work (alongside the more modern props approach I showed above):
This seems to get me the code snippets I'm after more or less (React): So it looks like for React I have a solution. However, and I could be wrong, but for Vue and Svelte, it seems I need either some sort of special storybook loader that I'm not aware of, or, I have to just create separate example files and then delegate to those. So here's a new ButtonsDisabled.vue view: <template>
<div>
<AgnosticButton label="Default Disabled" isDisabled />
<AgnosticButton mode="primary" label="Primary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Bordered Disabled" isBordered isDisabled />
</div>
</template>
<script>
import AgnosticButton from "./Button.vue";
export default {
name: "buttons-disabled",
components: { AgnosticButton },
};
</script> And then when I use that in my story like: import ButtonsDisabled from './ButtonsDisabled.vue';
export const ButtonsDisabledTest = (args) => ({
title: 'Buttons Disabled',
components: { ButtonsDisabled },
template: `<buttons-disabled />`,
}); I get this uninteresting rendering in terms of the code source example: So this last example was Vue, but I have similar results/issues with Svelte. It seems that I have to place the templates / views in another files e.g. |
If you write the code like this: export const Foo = () => <Button>bar</Button> The source code should show: () => <Button>bar</Button> In 6.0 we've introduced the Args construct, which you're using in the example above. As the Story function becomes more abstract, it gets further from what you'd want, as you note in the issue. In React, I've introduced dynamic snippet rendering, so that we render the JSX based on the live values of the args being passed into the function. So the if export const Foo = ({ children }) => <Button>{children}</Button> The source block would display: <Button>bar</Button> This was implemented in #11332. There are followup issues for some of the popular frameworks: #11400, #11588, #10617 If you're interested in contributing an implementation for your favorite framework, I'm happy to help guide. Otherwise, you can either use the non-args stories, or you can manually override the source snippet to be anything you want using the Would like to roll as many of these out as I can in 6.1. The current setup leaves a lot to be desired. |
Thanks for the timely reply sir! I see I'm not sure I can commit to contributing atm but I'll keep it in mind and can empathize that you'd prefer to shepherd collective ownership and contribution from the community! |
So I'm confused why React works so well (but Vue and Svelte do not) when I do something like this I get the snippet I'd expect: export const DisabledAll = () => (
<>
<Button label="Default Disabled" isDisabled />
<Button mode="primary" label="Primary Disabled" isDisabled />
<Button mode="secondary" label="Secondary Disabled" isDisabled />
<Button mode="secondary" label="Secondary Bordered Disabled" isBordered isDisabled />
</>
); The above two screen shots are perfect for my use case. So, after refactoring, React is working well for my use case. VueFirst, I cannot use JSX (or really <template>
<div>
<AgnosticButton label="Default Disabled" isDisabled />
<AgnosticButton mode="primary" label="Primary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Bordered Disabled" isBordered isDisabled />
</div>
</template>
<script>
// ButtonsDisabled.vue
import AgnosticButton from "./Button.vue";
export default {
name: "buttons-disabled",
components: { AgnosticButton },
};
</script> import ButtonsDisabled from './ButtonsDisabled.vue';
export default {
title: 'Button',
component: AgnosticButton,
// etc.
}
export const ButtonsDisabledAll = () => ({
title: 'Buttons Disabled',
components: { ButtonsDisabled },
template: `<buttons-disabled />`,
parameters: {
docs: {
source: {
code: `
<div>
<AgnosticButton label="Default Disabled" isDisabled />
<AgnosticButton mode="primary" label="Primary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Bordered Disabled" isBordered isDisabled />
</div>
`
}
}
}
}); Is this the expected output? You can see I've attempted to leverage the Also, it's not ideal since I have to manually duplicate the code. But I'm just trying things out. I haven't yet started trying to hack on the storybook codebase yet, but was hoping I wouldn't have to do so to achieve code snippets for Vue/Svelte. Lmk if there's anything I'm doing wrong or something else I can try before resorting to working on a patch upstream. Thanks for your guidance 🙏 |
Ok, I'm leaving all my user-land mistakes above in case someone else is having same issues :) Here's what fixed the export const ButtonsDisabledAll = () => ({
title: 'Buttons Disabled',
components: { ButtonsDisabled },
template: `<buttons-disabled />`,
});
ButtonsDisabledAll.parameters = {
docs: {
source: {
code: `
<div>
<AgnosticButton label="Default Disabled" isDisabled />
<AgnosticButton mode="primary" label="Primary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Disabled" isDisabled />
<AgnosticButton mode="secondary" label="Secondary Bordered Disabled" isBordered isDisabled />
</div>
`
}
},
} So this works pretty well for snippet in Docs tab: But for the Story tab: I suppose I could just go without using the addon-storysource since the Docs is showing the source there 🤔 -- still not ideal to have to manually copy code snippets into I also realized that if I comprimise with the export const Primary = Template.bind({});
Primary.args = {
label: 'Primary',
mode: 'primary',
};
Primary.parameters = {
docs: {
source: {
code: `<AgnosticButton mode="primary" label="Primary" />`
}
},
} In a way, this is closer to being satisfactory then the sub-view approach (if it's the best we can do), since the props and the hard coded I'm still wondering if there's a more ideal approach that will synchronize what's rendered w/source snippets better for Vue and Svelte. Any ideas or recommendations? |
yes I would also be really interested in having shown the exact source code of the generated vue-component over the written storysource code. Our developers would prefer to copy the snippet of the component. In the past we used the addon https://github.com/pocka/storybook-addon-vue-info. |
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks! |
This issue is still relevant. |
Yes, it will be nice when we no longer have to hard code the resulting template code which is error prone and tedious. I wish I had time to help with this but still do not. I'll leave it open for now. Thanks for chiming in to confirm it's still relevant @curtgrimes |
@netzfluencer Dynamic snippet rendering for Vue has been implemented in 6.1 in #12812 using an improvement on @curtgrimes @roblevintennis if either of you is interested in implementing this for the framework of your choice, I'd be happy to help guide. |
Does this work or how do you activate? I'm still getting this in source after updating to latest: (args, { argTypes }) => ({
components: { EnDropdown },
props: Object.keys(argTypes),
template: `<EnDropdown v-bind="$props"></EnDropdown>`,
}) |
We’re cleaning house! Storybook has changed a lot since this issue was created and we don’t know if it’s still valid. Please open a new issue referencing this one if:
|
To whoever ends up here without a solution here's mine. I'm on Storybook 8.4.x and i use Vite with React. Luckly we have Claude and other LLMs so i was able to make it work. Instead of relying on storybook's source generation i copy-paste the code manually into Custom addon file: .storybook/addons/source-tab/manager.tsx import React from "react";
import { addons, types } from "@storybook/manager-api";
import { AddonPanel } from "@storybook/components";
import { Source } from "@storybook/blocks";
import { useStorybookApi, useStorybookState } from "@storybook/manager-api";
import { useTheme } from "@storybook/theming";
const ADDON_ID = "storybook/source-tab";
const PANEL_ID = `${ADDON_ID}/panel`;
const SourcePanel = () => {
const api = useStorybookApi();
const state = useStorybookState();
const theme = useTheme();
const story = api.getData(state.storyId, state.refId);
if (!story) {
return null;
}
return (
<div style={{ padding: "1rem" }}>
<Source
code={story.parameters?.docs?.source?.code || "// No source available"}
language="tsx"
dark={theme.base === "dark"}
/>
</div>
);
};
addons.register(ADDON_ID, () => {
addons.add(PANEL_ID, {
type: types.PANEL,
title: "Source",
render: ({ active }) => (
<AddonPanel active={active || false}>
<SourcePanel />
</AddonPanel>
),
});
}); My .storybook/main.ts import type { StorybookConfig } from "@storybook/react-vite";
const config: StorybookConfig = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
addons: [
"@storybook/addon-onboarding",
{
name: "@storybook/addon-essentials",
options: {
actions: false,
interactions: false,
controls: false,
},
},
"@chromatic-com/storybook",
"storybook-dark-mode",
"./addons/source-tab/manager.tsx",
],
framework: {
name: "@storybook/react-vite",
options: {},
},
};
export default config; My stories then look like this: export const Primary: Story = {
args: {
variant: "primary",
children: <SybButtonText>Button</SybButtonText>,
},
parameters: {
controls: {
exclude: [...excluded_controls_non_default_stories, "variant"],
},
docs: {
source: {
code: source`
<SybButton variant="primary">
<SybButtonText>Button</SybButtonText>
</SybButton>
`,
},
},
},
}; This is the result May seem a nightmare to maintain but actually is not, I use cursor and ask it to generate all the stories for me and keep the source up to date. |
Is your feature request related to a problem? Please describe.
I've been following the tutorials and docs to create many stories using the props driven pattern described there. I have projects in React, Svelte, and Vue, and each have their own storybook with similar configurations.
Using the prescribed patterns in the featured storybook docs/tutorials this is the approach I've used (it's Svelte based, but I've mostly done the same thing for React and Vue with similar results):
When I show code or look at the addon-storysource I see the template code which won't be a helpful dev ux for readers of my design system. Note the examples are really showing the
Template
intermediary component and are all the same:and same for the addon-storysource tab:
Describe the solution you'd like
I'm listing this as a feature as I believe the addon is working as designed. However, I'm confused on the overall result—if this props driven approach to testing is the recommendation, but the code snippet examples derived are essentially meaningless to the dev users, how am I able to achieve the goal of documenting how to use a component?
As a previous user of react-styleguidist (and other similar tools), getting code snippets was fairly trivial. For styleguidist, it would simply output the code blocks within your markdown giving you some control of what the user would see.
I'm fairly new to storybook but have already written a slew of these stories so I'm hoping I've missed something in the usage somehow.
Describe alternatives you've considered
I've seen some older storiesOf examples that seem to use the template or jsx more closely and wonder if those output better code examples. However, I've written so many of these stories using the docs recommended way that it would be a bear to refactor them all, especially if I'm using an older less idiomatic approach then the props driven newer one that's clearly being featured on the docs and tutorial pages for storybook.
Are you able to assist bring the feature to reality?
no | yes, I can...
Additional context
To be clear, I'd expect the source code examples to show something more meaningful like this I've taken from another similar project I've worked on:
The text was updated successfully, but these errors were encountered: