storybookjs / storybook

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

[Bug]: Unable to access context in docs.container #20634

Open will-stone opened 1 year ago

will-stone commented 1 year ago

Describe the bug

Hi,

We were running v7 beta 13 and just tried updating to beta 28. We use the docs.container to wrap-up a repeated documentation introduction. We are now unable to read from context.storyById(), where we get the following error:

Error: No primary story defined for docs entry. Did you forget to use `<Meta>`

This is despite our *.mdx file containing <Meta of={Stories} /> line.

To Reproduce

Reproduction:

https://github.com/will-stone/storybook-docs-container-bug

The offending line: https://github.com/will-stone/storybook-docs-container-bug/blob/main/.storybook/preview.jsx#L4

The MDX file with the `Meta` component: https://github.com/will-stone/storybook-docs-container-bug/blob/main/src/stories/Button.mdx?plain=1#L5

System

System:
    OS: macOS 12.6.2
    CPU: (10) arm64 Apple M1 Max
  Binaries:
    Node: 18.12.1 - ~/.local/share/nvm/v18.12.1/bin/node
    npm: 8.19.2 - ~/.local/share/nvm/v18.12.1/bin/npm
  Browsers:
    Chrome: 108.0.5359.124
    Firefox: 108.0.2
    Safari: 16.2
  npmPackages:
    @storybook/addon-essentials: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/addon-interactions: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/addon-links: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/blocks: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/react: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/react-vite: ^7.0.0-beta.28 => 7.0.0-beta.28
    @storybook/testing-library: ^0.0.13 => 0.0.13

Additional context

Being able to access context in the docs.container is incredibly useful, as it means we can have story-aware conditional logic in there.

ezzatron commented 1 year ago

I think we're experiencing the same issue. We were using docs.container to integrate storybook-dark-mode with standalone docs pages. Our pages have <Meta>, yet we get the same error:

Error: No primary story defined for docs entry. Did you forget to use `<Meta>`?
    at DocsContext.storyById (http://localhost:3000/sb-preview/runtime.js:82:803)
    at container (http://localhost:3000/main.iframe.bundle.js:78:21)
    at renderWithHooks (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:65004:18)
    at mountIndeterminateComponent (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:68768:13)
    at beginWork (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:70281:16)
    at beginWork$1 (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:76120:14)
    at performUnitOfWork (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:75251:12)
    at workLoopSync (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:75160:5)
    at renderRootSync (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:75128:7)
    at recoverFromConcurrentError (http://localhost:3000/vendors-node_modules_storybook_addon-docs_dist_index_mjs-node_modules_storybook_addon-essenti-2ee5bf.iframe.bundle.js:74544:20)

The code in our docs.container that's calling storyById():

const preview: Preview = {
    // ...
    docs: {
      container: ({ children, context }) => {
        const isDark = useDarkMode();

        const { id, storyById } = context;
        const story = storyById(id);
        const { parameters } = story;
        const { docs } = parameters;
        docs.theme = isDark ? themes.dark : themes.light;

        // see https://github.com/storybookjs/storybook/issues/8622
        // no dependencies on this effect is deliberate
        // otherwise it won't run when the docs page is re-activated
        useEffect(() => {
          // if docs-root is hidden that means the docs page is not active
          // for some reason this component never gets unmounted
          if (document.getElementById("docs-root")?.hidden) return;

          document.body.classList.remove("dark", "light");
          document.documentElement.dataset.theme = isDark ? "dark" : "light";
        });

        return <DocsContainer context={context}>{children}</DocsContainer>;
      },
    },
}
shilman commented 1 year ago

@ezzatron Do you a have a reproduction repo you can share? If not, can you create one? Go to https://storybook.new or see repro docs. Thank you! 🙏

ezzatron commented 1 year ago

Not to pass the buck, but the original issue description has a nice repro already. For our specific issue, it seems like other changes in Storybook 7 removed the need for us to call storyById(), which fixed our problem. Sorry for the noise!

AngusMacrae commented 1 year ago

I am also encountering the same issue - calling storyById() in a custom docs container in an unattached docs page throws the error as described above.

However, before Storybook 7, we could access meta data like parameters or title directly on the context object, and this is no longer possible. I can't find any documentation indicating how we are supposed to do this now in SB7.

E.g. in version 6 we could do:

export const DocsContainer: ({children, context}) => {

const title = context?.title;
const myParameter = context?.parameters?.myParameter;

.....
}

In attached docs now we can replace context with context.storyById() to get a reference to the primary story and it works ok. But in unattached docs this throws an error. There is a property on the context object called attachedCsfFile which seems to contain the meta data but it is not documented anywhere and is not included in the typescript typings either.

Anyone know what the "correct" approach is now in SB7?

mogamogua commented 1 year ago

I also encountered same issue.

I was trying to get context's globals which was abled to get by this method:

const story = context.storyById();
const {globals} = context.getStoryContext(storyId);

but I found that I can approach global parameter directly by contexxt.store.globals.globals; However, DocsContextProps type doesn't include this property. so I just use any type assertion.

const {globals} = (context as any).store.globals;

I'm not sure is it valid approach, but I hope someone could get help by this method.

github-actions[bot] commented 1 year ago

Hi there! Thank you for opening this issue, but it has been marked as stale because we need more information to move forward. Could you please provide us with the requested reproduction or additional information that could help us better understand the problem? We'd love to resolve this issue, but we can't do it without your help!

CalebBarnes commented 1 year ago

For anyone else who was also trying to change theme for docs with storybook-dark-mode in storybook 7^, here is an example of my preview.tsx

This toggles the theme for the sidebar/toolbar, the docs pages, and also adding the dark/light classname to the individual story preview (customize this to fit your app).

import "../src/app/globals.css";
import "./font-mock.css";

import React from "react";
import { useDarkMode } from "storybook-dark-mode";
import { themes } from "@storybook/theming";
import { DocsContainer } from "@storybook/blocks";
import type { Preview } from "@storybook/react";

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },

    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },

    // theme for docs pages
    viewMode: "docs",
    docs: {
      container: ({ children, context }) => {
        return (
          <DocsContainer
            context={context}
            theme={useDarkMode() ? themes.dark : themes.normal}
          >
            {children}
          </DocsContainer>
        );
      },
    },

    // theme for controls and side panel
    darkMode: {
      current: "dark",
      dark: themes.dark,
      light: themes.normal,
      stylePreview: true,
    },
  },

  // theme for stories
  decorators: [
    (Story) => (
      <div className={useDarkMode() ? "dark" : "light"}>
        <Story />
      </div>
    ),
  ],
};

export default preview;
AngusMacrae commented 1 year ago

Hi there! Thank you for opening this issue, but it has been marked as stale because we need more information to move forward. Could you please provide us with the requested reproduction or additional information that could help us better understand the problem? We'd love to resolve this issue, but we can't do it without your help!

There is a repro already provided by the original poster. Besides, this is a general issue, the parameters and meta info of unattached docs files are not exposed on the context object except as (context as any).attachedCSFFile. meta which is hacky and not type safe.

Prior to SB7 these values were easily accessible directly on the context object.

shilman commented 1 year ago

Sorry for the long delay here & confusion about the reproduction.

I looked into the original reproduction (upgraded to 7.4) and it looks like a race condition. There is logic to get the story object if the primary story is set, but it looks like the primary story is not set until after the first render, at which point the docs container has already errored out. I'll see if I can pair with @tmeasday to see if there's a quick fix.