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

[Bug]: vue3 story sourcecode does not reflect the preview #21129

Closed
KevinCarnaille2 opened this issue Feb 16, 2023 · 22 comments · Fixed by #22518
Closed

[Bug]: vue3 story sourcecode does not reflect the preview #21129

KevinCarnaille2 opened this issue Feb 16, 2023 · 22 comments · Fixed by #22518

Comments

@KevinCarnaille2
Copy link

KevinCarnaille2 commented Feb 16, 2023

Describe the bug

In vue3 + Storybook 7.0.0-beta.48 context (edit : same issue with beta 51)

When we declare a story with static properties, and without any args, the sourcecode is not rendering correctly (preview is fine though) :

  • static properties are not rendered
  • slots are not rendered

Simple example with a Button component, having multiple variants that I need to display in one story :

export const Variants = {
    render: (args) => ({
        components: { MyButton },
        setup() {
            return {
                args,
            }
        },
        template: `
            <MyButton variant="primary">Primary</MyButton>  
            <MyButton variant="secondary">Secondary</MyButton>  
        `,
    }),
}

Generated sourcecode :

<MyButton />
<MyButton />  

I have a different behavior when I declare the slot like so :

export const Variants = {
    render: (args) => ({
        components: { MyButton },
        setup() {
            return {
                args,
            }
        },
        template: `
            <MyButton variant="primary">{{args.defaultSlot}}</MyButton>  
            <MyButton variant="secondary">{{args.defaultSlot}}</MyButton>  
        `,
    }),
    args: {
        defaultSlot: 'Button',
    }
}

Generated sourcecode :

<MyButton variant="primary" />
<MyButton variant="secondary" />  

This time the variant property is correctly displayed, but still not for the slot.

To Reproduce

https://github.com/KevinCarnaille2/sb-vue3-sourcecode-issue

No response

System

Environment Info:
  Binaries:
    Node: 16.17.1 - ~/.nvm/versions/node/v16.17.1/bin/node
    npm: 8.15.0 - ~/.nvm/versions/node/v16.17.1/bin/npm
  npmPackages:
    @storybook/addon-docs: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/addon-essentials: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/addon-interactions: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/addon-links: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/addons: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/channel-postmessage: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/channel-websocket: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/client-api: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/preview-web: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/testing-library: 0.0.13 => 0.0.13 
    @storybook/vue3: 7.0.0-beta.48 => 7.0.0-beta.48 
    @storybook/vue3-vite: 7.0.0-beta.48 => 7.0.0-beta.48

Additional context

No response

@KevinCarnaille2
Copy link
Author

At the moment, the only way to properly display the source code is to store the template in a const, and reapply this const to the parameters.docs...

const template = `
<MyButton variant="primary">Primary</MyButton>  
<MyButton variant="secondary">Secondary</MyButton>  
`;

export const Variants = {
    render: (args) => ({
        components: { MyButton },
        setup() {
            return {
                args,
            }
        },
        template,
    }),
    parameters: {
       docs: {
          source: {
               code: template
          }
       }
    }
};

@chakAs3 chakAs3 self-assigned this Feb 19, 2023
@chakAs3
Copy link
Contributor

chakAs3 commented Feb 19, 2023

HI @KevinCarnaille2 can you share yourButton.vuecode source i need to look at it

@KevinCarnaille2
Copy link
Author

HI @KevinCarnaille2 can you share yourButton.vuecode source i need to look at it

Sure @chakAs3 ! Here it is ! The types imported are generated union string, based on arrays.

<template>
    <component
        :is="attrs.href ? 'a' : 'button'"
        :disabled="attrs.disabled"
        :class="[
            'my-button',
            `my-button_${variant}`,
            `my-button_${size}`
        ]"
    >
        <span class="my-button--slot">
            <slot />
        </span>
    </component>
</template>

<script setup lang="ts">
    import {BUTTON_VARIANTS, BUTTON_SIZES, ButtonSizes, ButtonVariants} from './MyButton.types';
    import {PropType, useAttrs, computed} from 'vue';

    const props = defineProps({
        variant: {
            type: String as PropType<ButtonVariants>,
            default: 'primary',
            validator(variant: ButtonVariants) {
                return BUTTON_VARIANTS.includes(variant);
            },
        },
        size: {
            type: String as PropType<ButtonSizes>,
            default: 'medium',
            validator(variant: ButtonSizes) {
                return BUTTON_SIZES.includes(variant);
            },
        },
    });

    const attrs = useAttrs();
</script>

<style scoped lang="scss">
</style>

@chakAs3
Copy link
Contributor

chakAs3 commented Feb 21, 2023

Hi @KevinCarnaille2 your repo was not really a reproduction one, cause it is missing project configuration can't see either vite or storybook configuration.
so i created one for you using
yarn create vite my-vue-app --template vue
then I run storybook init with next branch ( 7.0.0.beta50)
npx sb@next init
this will automatically detect your project configuration and install the right version of storybook with initial config and stories templates to get started

i copied the stories folder from your repo and tested it was giving me this
image

which is perfect as the variant prop no need to pass as it is the default value = primary
image

if you change the value it will reflect on the source
image

same if you fill the other props in the control
image

@chakAs3
Copy link
Contributor

chakAs3 commented Feb 21, 2023

here is a fork of your repo with my change to be able to test yourself
https://github.com/chakAs3/sb-vue3-sourcecode-issue

@KevinCarnaille2
Copy link
Author

KevinCarnaille2 commented Feb 21, 2023

Hello @chakAs3 I have updated the repository with a full vue3/ts/vite/storybook setup.

Hope this is enough :)
There are 3 cases I tried to detail as much as possible !

@riovir
Copy link

riovir commented Feb 23, 2023

I've encountered a similar problem with non-component HTML added to the story. Here is a use case for a design system:
There is a notification component: DsNotification. It comes and goes usually with a v-if directive. For proper screen reader use however, it has to be contained within a parent with the role attribute set to status or alert depending on the severity.

Here is the source of the story:

const render = args => ({
	template: `
		<div :role="variant === 'danger' ? 'alert' : 'status'">
			<ds-notification v-if="isVisible" v-bind="{ variant, prominent, header, content, hideCloseButton }" />
		</div>
	`,
	components: { DsNotification },
	props: {
		isVisible: { type: Boolean, required: true }, // controlled by a decorator, no problem there
	},
	setup: () => args,
});

The generated source ends up being with the role stripped from the div:

<template>
  <div>
    <ds-notification
      variant="danger"
      header="Title of the notification"
      content="Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
      v-on:close="() => {}"
    />
  </div>
</template>

I'd expect the role to be presented as well:

<template>
  <div role="alert">
    <ds-notification
      variant="danger"
      header="Title of the notification"
      content="Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
      v-on:close="() => {}"
    />
  </div>
</template>

Copy link
Contributor

chakAs3 commented Feb 24, 2023

Hi yes I’m opening a pr to fix this. With extra tests :

@KevinCarnaille2
Copy link
Author

Hi yes I’m opening a pr to fix this. With extra tests :

Are you talking about this specific PR ?
#21273

Copy link
Contributor

chakAs3 commented Mar 4, 2023

yes @KevinCarnaille2

@KevinCarnaille2
Copy link
Author

Do we have any news about this ?
I've updated to the last RC, and I'm still having the same slots issues, with sourcecode not reflecting what he give in entry

@chakAs3
Copy link
Contributor

chakAs3 commented Mar 30, 2023

Do we have any news about this ? I've updated to the last RC, and I'm still having the same slots issues, with sourcecode not reflecting what he give in entry

Hi @KevinCarnaille2 We are going soon to merge the PR that fixes that, or maybe i can split the large PR to accommodate only the source code feature.

Copy link
Contributor

chakAs3 commented Apr 4, 2023

Hi. @KevinCarnaille2 can you pull this repo and test the source snippet and let me know if this is fine https://github.com/storybookjs/vue3-vuetify-examples

@KevinCarnaille2
Copy link
Author

Hi. @KevinCarnaille2 can you pull this repo and test the source snippet and let me know if this is fine https://github.com/storybookjs/vue3-vuetify-examples

Thans for this !
There are a lot examples to test , but here are my first feedbacks :

  • the Primary story is working well, with the "h" rendered
  • the Secondary has some issues, the slot display is weird with additional brackets

secondary-sb7

  • the MultiComponents snippet is failing when you play with "subcomponents" v-bind and subargs

multicomponents-sb7

@chakAs3 chakAs3 mentioned this issue Apr 5, 2023
5 tasks
@KevinCarnaille2
Copy link
Author

Hello!
I gave it a try with my project as well.

Storybook version: 7.0.4
I use PNPM 7.13.2

It's better ! But I still struggle with named slots.
I'm currently working on a Side panel component, for the context.
I have a title, subtitle, and body slots....

Here is my story code, I've followed what you've done and I used the h renderer function :

import MySidePanel from './MySidePanel.vue';
import {h} from 'vue';

export default {
    title: 'Overlay/MySidePanel',
    component: MySidePanel,
};

export const Default = {
    args: {
        'open': false,
        'side-panel-trigger': h('button', {}, 'Trigger'),
        'side-panel-title': h('h3', {}, 'I am the title'),
        'side-panel-subtitle': h('p', {}, 'I am the subtitle with a description),
    },
};

The rendering is fine, but the generated code snippet looks like so :

<template>
  <MySidePanel>
    <template #side-panel-trigger>
      {"__v_isVNode":true,"__v_skip":true,"type":"button","props":{},"key":null,"ref":null,"scopeId":null,"slotScopeIds":null,"children":"Trigger","component":null,"suspense":null,"ssContent":null,"ssFallback":null,"dirs":null,"transition":null,"el":null,"anchor":null,"target":null,"targetAnchor":null,"staticCount":0,"shapeFlag":9,"patchFlag":0,"dynamicProps":null,"dynamicChildren":null,"appContext":null,"ctx":null}
    </template>
    <template #side-panel-title>
      {"__v_isVNode":true,"__v_skip":true,"type":"h3","props":{},"key":null,"ref":null,"scopeId":null,"slotScopeIds":null,"children":"I
      am the
      header","component":null,"suspense":null,"ssContent":null,"ssFallback":null,"dirs":null,"transition":null,"el":null,"anchor":null,"target":null,"targetAnchor":null,"staticCount":0,"shapeFlag":9,"patchFlag":0,"dynamicProps":null,"dynamicChildren":null,"appContext":null,"ctx":null}
    </template>
    <template #side-panel-subtitle>
      {"__v_isVNode":true,"__v_skip":true,"type":"p","props":{},"key":null,"ref":null,"scopeId":null,"slotScopeIds":null,"children":"I
      am the subtitle with a
      description","component":null,"suspense":null,"ssContent":null,"ssFallback":null,"dirs":null,"transition":null,"el":null,"anchor":null,"target":null,"targetAnchor":null,"staticCount":0,"shapeFlag":9,"patchFlag":0,"dynamicProps":null,"dynamicChildren":null,"appContext":null,"ctx":null}
    </template>
  </MySidePanel>
</template>

And I have this warning :

[Vue warn]: Extraneous non-props attributes (side-panel-trigger, side-panel-title, side-panel-subtitle, side-panel-confirm, side-panel-cancel) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.

I don't really get what's going on because when I try with your repository, I don't have the issue.
If it's not clear enough I can try to update my test/public repository with the right versions.

Copy link
Contributor

chakAs3 commented Apr 13, 2023

hi @KevinCarnaille2 i see what are doing, seems ok, i know why the component code is rendered as VNode i have to check back with your test, for here i can see it not big deal i will get back to you . and this fixed in the patch i put on the repo i shared with you. you can contribute there with you case an open a PR, it will be helpful 😃
https://github.com/storybookjs/vue3-code-examples

@Nagell
Copy link

Nagell commented May 15, 2023

I've also experienced some issues with template rendering but the case is slightly different.
It's about <component :is="someComponent" />:

import OhIconTeaser, { Props } from "./OhIconTeaser.vue";
import type { Meta, StoryObj, VueRenderer } from "@storybook/vue3";
import { OhIconAlertCircle } from "../../icons";

import { reactive } from 'vue'
import * as icons from '../../icons'

const meta: Meta<Props & {icon: string}> = {
    // ...
    render: args => ({
        components: { OhIconTeaser },
        setup() {
            const iconsArr = reactive<Record<string, any>>(icons)
            return { args, iconsArr };            
        },
        template: `
	<OhIconTeaser v-bind="args">
		<template #icon>      
                        <component :is="(iconsArr[args.icon])" />
		</template>
	</OhIconTeaser>
	`,
    }),
    argTypes: {

        //  ...

        icon: {
            options:  Object.keys(icons),
            control: {
                type: "select",
            }
        },
    },
    args: {

        //  ...

        icon: "OhIconAlertCircle",
    },
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
    args: {},
};

Originally the component looks like this:

<template>
    <a :href="link ?? '#'" :target="target">
        <div class="oh-icon-teaser">
            <slot name="icon" />
            <h2 class="oh-icon-teaser__title">{{ title }}</h2>
            <p class="oh-icon-teaser__content">{{ content }}</p>
        </div>
    </a>
</template>

Rendered sourcecode looks like this:

<template>
  <OhIconTeaser
    title="Sit back and relax"
    content="Let companies do the applying. You stay in control and decide which opportunities to pursue further."
    link="#"
  >
    "OhIconAlertCircle"
  </OhIconTeaser>
</template>

and should like this instead:

<template>
  <OhIconTeaser
    title="Sit back and relax"
    content="Let companies do the applying. You stay in control and decide which opportunities to pursue further."
    link="#"
  >
    <OhIconAlertCircle />
  </OhIconTeaser>
</template>

Unnamed slots are even worse:

Component:

<template>
    <a class="oh-btn-icon" :class="[sizeClasses]">
        <slot />
         <!-- <slot name="default"/> makes the same -->
    </a>
</template>

Story:

    render: args => ({
        components: { OhButtonIcon },
        setup() {
            const icons = reactive<Record<keyof typeof iconsModule, any>>(iconsModule)
            return { args, icons };
        },
        template: `
          <OhButtonIcon v-bind="{size: args.size}">
                <template #default>
                    <component :is="(icons[args.icon])" />
                </template>
            </OhButtonIcon>
        `,
    }),

Preview:

<template>
  <OhButtonIcon size="md" icon="OhIconAlertCircle" />
</template>

Copy link
Contributor

chakAs3 commented May 22, 2023

Hi @Nagell , first thank you for your detailed feedback, actually the PR that addresses source decorator not yet merged to 'next' branch, here is the PR #22518 .
Anyway i will be testing your code to see if we still have this issue on the recent PR

@KevinCarnaille2
Copy link
Author

@chakAs3 I see the issue is closed. Which SB version includes the fix :) ?

Copy link
Contributor

chakAs3 commented Jun 20, 2023

hi @KevinCarnaille2 how are doing. long time 😄. it is already on latest version

@KevinCarnaille2
Copy link
Author

hi @KevinCarnaille2 how are doing. long time smile. it is already on latest version

Hello hello :D
Nice to read this, it's included in the 7.1 alpha right ?

@chakAs3
Copy link
Contributor

chakAs3 commented Jun 21, 2023

hi @KevinCarnaille2 how are doing. long time smile. it is already on latest version

Hello hello :D Nice to read this, it's included in the 7.1 alpha right ?

yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
6 participants