storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.8k stars 9.33k forks source link

[Bug]: Vue3 After upgrading to V7 (and v8) controls are not reactive #26876

Open shaniqwa-drm opened 7 months ago

shaniqwa-drm commented 7 months ago

Describe the bug

When I change the controls, nothing happens. This issue started after migration from v6 to v7. Now I'm on the latest v8, all my dependencies are up-to-date, and this issue remains.

https://github.com/storybookjs/storybook/assets/124711028/fc0c797d-9a66-452d-a740-f68b21622eea

sharing my config and preview settings: main.ts

import path from "path";
import VueTypeImports from "vite-plugin-vue-type-imports";
import eslint from "vite-plugin-eslint";
import type { StorybookConfig } from '@storybook/vue3-vite';

const tailwindConfigPath = path.join(__dirname, "../tailwind.config.js"); // or your own config file
require("storybook-tailwind-foundations/initialize.js")
  .default(tailwindConfigPath);

const config: StorybookConfig = {
  framework: "@storybook/vue3-vite",
  stories: [
    "../node_modules/storybook-tailwind-foundations/**/*.stories.js",
    "../src/**/*.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  addons: [
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/addon-mdx-gfm"
  ],
  docs: {
    autodocs: 'tag',
    defaultName: "Documentation",
  },
  viteFinal: async (config: any) => {
    config.css = {
      preprocessorOptions: {
        scss: {
          additionalData: "@import \"@/style/mixin.scss\";",
        },
      },
    };
    config.plugins.push(
      eslint({
        exclude: ["/virtual:/**", "node_modules/**"],
      }),
      VueTypeImports()
    );
    config.resolve.alias = {
      ...config.resolve.alias,
      "~": path.resolve(__dirname, "../"),
      "@": path.resolve(__dirname, "../src"),
    };
    return config;
  }
};

export default config

preview.js:

import {darkTheme, NConfigProvider, NMessageProvider} from "naive-ui";
import {setup} from "@storybook/vue3";
import {createPinia} from "pinia";
import themeOverrides from "@/constants/Naive-ui-theme-overrides";
import "../src/style/style.scss";
import {h} from "vue";
import {clickOutside} from "@/directives/clickOutside";
import {scrollToBottom} from "@/directives/scrollToBottom";
import {can} from "@/directives/can";
import {createSocketPlugin} from '@/plugins/socketPlugin'
import {provideSocket} from '@/hooks/useSocket'
import {useSocketMock} from './__mocks__/useSocket'
import {socketFunctions} from '@/hooks/useSocket'
import {vueRouter} from "storybook-vue3-router";
import mockRoutes from "@/stories/mockRoutes";
import {createWebHistory} from "vue-router";

Object.assign(socketFunctions, {
  useSocket: useSocketMock,
});

setup((app) => {
// make sure naive-ui is loaded after tailwind [https://www.naiveui.com/en-US/dark/docs/style-conflict] but before app
  const meta = document.createElement("meta");
  meta.name = "naive-ui-style";
  document.head.appendChild(meta);

  const pinia = createPinia();

  app.use(pinia);
  app.use(createSocketPlugin())

  provideSocket(app)
  app.directive("click-outside", clickOutside);
  app.directive("scroll-to-bottom", scrollToBottom);
  app.directive("can", can);

});

export const parameters = {
  backgrounds: {
    default: "gray-800",
    values: [
      {
        name: "gray-800",
        value: "#323249",
      },
      {
        name: "gray-1000",
        value: "#26263B",
      }
    ],
  },
  actions: {argTypesRegex: "^on[A-Z].*"},
  controls: {
    expanded: true,
    sort: 'requiredFirst',
    matchers: {
          color: /(background|color)$/i,
          date: /Date$/,
        },
  },
  decorators: [
    (story, context) => {
      provideSocket(context); // Provide the necessary service
      return story();
    },
  ]
};

/**
 * apply naive-ui theme + theme overrides to all stories
 */
export const decorators = [
  vueRouter(mockRoutes, {
    vueRouterOptions: {
      linkActiveClass: 'activeLink',
      routes: mockRoutes,
      history: createWebHistory(import.meta.env.BASE_URL),
    },
  }),
  () => ({
    template:
      `<div class="font-sans"><story/></div>`
  }),
  (story) => h(
    NMessageProvider,
    {},
    () => h(story())
  ),
  (story) => h(
    NConfigProvider,
    {
      theme: darkTheme,
      themeOverrides: themeOverrides
    },
    () => h(story())
  )
];

To Reproduce

Unfortunately, I don't know how to reproduce this issue. I'm sure a new, small project from scratch will work, but I guess something in the process of migrating between different version broke the feature.versions

System

System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M2
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 21.2.0 - /opt/homebrew/bin/node
    Yarn: 4.0.2 - /opt/homebrew/bin/yarn <----- active
    npm: 10.2.3 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 123.0.6312.124
    Safari: 17.4.1
  npmPackages:
    @storybook/addon-essentials: ^8.0.6 => 8.0.8 
    @storybook/addon-interactions: ^8.0.6 => 8.0.8 
    @storybook/addon-mdx-gfm: ^8.0.6 => 8.0.8 
    @storybook/blocks: ^8.0.6 => 8.0.8 
    @storybook/cli: ^8.0.6 => 8.0.8 
    @storybook/test: ^8.0.6 => 8.0.8 
    @storybook/test-runner: ^0.17.0 => 0.17.0 
    @storybook/vue3: ^8.0.6 => 8.0.8 
    @storybook/vue3-vite: ^8.0.6 => 8.0.8 
    eslint-plugin-storybook: ^0.8.0 => 0.8.0 
    storybook: ^8.0.6 => 8.0.8 
    storybook-tailwind-foundations: ^1.1.2 => 1.1.2 
    storybook-vue3-router: ^5.0.0 => 5.0.0

Additional context

lentilz commented 1 month ago

Not sure of the relevance but I experienced this when updated my project from Vue 2/ Storybook 7 --> Vue 3/Storybook 8.3. We had instances were we passed new values to props when another arg is changed. I realized that in the new vue3 set up, I need to wrap the update in a watcher to resolve this. Video recording of the issue we had: https://www.awesomescreenshot.com/video/32229387?key=be636f8a868c96d2d4886e871232d0de

Original code:

            setup() {
                if (args.alert) {
                    args.alert['type'] = args.toggleAlertType;
                }
                return { args };
            },
            template: '<BaseAlert v-bind="args" />'

Solution:

setup() {
                watch(
                    () => args.toggleAlertType,
                    (updatedAlert) => {
                        if (args.alert) {
                            args.alert['type'] = updatedAlert;
                        }
                    }
                );

                return { args };
            },