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

Addon Docs subcomponents support for sub element components #9444

Closed
blind76 opened this issue Jan 14, 2020 · 25 comments
Closed

Addon Docs subcomponents support for sub element components #9444

blind76 opened this issue Jan 14, 2020 · 25 comments

Comments

@blind76
Copy link

blind76 commented Jan 14, 2020

Is your feature request related to a problem? Please describe.
I use Component.SubComponent for my components and I want to show prop tables for subcomponents and as far as I can see that is not supported

Describe the solution you'd like
I would suggest supporting something like:
subcomponents: {'Component.SubComponent': Component.SubComponent}

Are you able to assist bring the feature to reality?
I can...

@shilman
Copy link
Member

shilman commented Jan 14, 2020

@blind76 This is already supported, e.g.

https://github.com/storybookjs/storybook/blob/next/examples/official-storybook/stories/addon-docs/subcomponents.stories.js

@shilman shilman closed this as completed Jan 14, 2020
@blind76
Copy link
Author

blind76 commented Jan 14, 2020

@shilman It is but for exported regular Components and not for sub-components.
In my case that would be something like:

import Component from '../Component';

export default {
	component: Component,
	subcomponents: Component.SubComponent
};

export const someStory = () => (
<Component>
     <Component.SubComponent>Content of subcomponent</Component.SubComponent>
</Component>
);

@shilman
Copy link
Member

shilman commented Jan 15, 2020

@blind76 this doesn't work?

import Component from '../Component';

export default {
	component: Component,
	subcomponents: { SubComponent: Component.SubComponent },
};

export const someStory = () => (
<Component>
     <Component.SubComponent>Content of subcomponent</Component.SubComponent>
</Component>
);

@blind76
Copy link
Author

blind76 commented Jan 15, 2020

@shilman no it's not.
I get the tabs and subcomponents have correct tab titles but the primary component has title "Undefined".

Primary component (tab Undefined) has correct props table but other tabs just say "No props found for this component"

@shilman
Copy link
Member

shilman commented Jan 16, 2020

Ah, add a default.title to the previous example to get a tab title for the main component. You need that anyway in CSF.

As for the prop support for subcomponents, can you share the source of Component + Component.SubComponent?

@shilman shilman reopened this Jan 16, 2020
@blind76
Copy link
Author

blind76 commented Jan 20, 2020

@stale
Copy link

stale bot commented Feb 10, 2020

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!

@stale stale bot added the inactive label Feb 10, 2020
@Smolations
Copy link

Smolations commented Feb 11, 2020

@shilman I am so psyched this is a feature! However, I don't think the main component's tab (the first one) actually keys off the title. For me, it seems to be keying off the functional component name or the Component.displayName (which matches the component function name). My "pseudo-main" component is a state container for the main component, so I have:

// MainComponent/index.js

// MainComponentContainer.displayName = 'MainComponentContainer'
import MainComponentContainer from './MainComponentContainer'; 
import SubComponent from './SubComponent';
// ...other subcomponents...

const MainComponent = MainComponentContainer;

MainComponent.SubComponent = SubComponent;
// ...

export {
  MainComponent,
};

And then my story file:

export default {
  title: 'Components|MainComponent',
  component: MainComponent,
  subcomponents: {
    'MainComponent.SubComponent': MainComponent.SubComponent,
    // ...
};

The subcomponent tab renders according to the key I set as expected, but the first tab ends up being "MainComponentContainer." Is the title the only way to affect that first tab's name or is there another way?

EDIT: Just confirmed the tab name is coming from MainComponentContainer.displayName. I could lie to the code and finagle the names, but I would much prefer to have the option to override the tab title. 😁

Also, is there any way to get a subcomponent's description to show up above the props table when its tab is selected? Would be a nice-to-have...

@stale stale bot removed the inactive label Feb 11, 2020
@shilman
Copy link
Member

shilman commented Feb 12, 2020

@Smolations Yeah this looks like a bug. I'd rather not introduce another parameter for naming the component tab -- if the bug was fixed would that be sufficient for your use case?

@blind76
Copy link
Author

blind76 commented Feb 12, 2020

@Smolations do you have props table for subcomponents or it says: "No props found for this component
"?

@Smolations
Copy link

Smolations commented Feb 12, 2020

if the bug was fixed would that be sufficient for your use case?

@shilman if that would cause the first tab to be named MainComponent, then absolutely! 😁

@blind76 My props tables are showing up as expected. Are yours not?

Also, I'm on 5.3.12 and looking forward to 6.0.0. 😋

@stale
Copy link

stale bot commented Mar 4, 2020

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!

@stale stale bot added the inactive label Mar 4, 2020
@shilman shilman added the todo label Mar 4, 2020
@stale stale bot removed the inactive label Mar 4, 2020
@Pete-Robelou
Copy link

@shilman Should this also work when writing stories in MDX?

I've tried this but it's not working

<Meta title="Components/Label" component={Label} subcomponents={LabelCaption} />

@shilman
Copy link
Member

shilman commented Apr 22, 2020

@Pete-Robelou should work with:

<Meta title="Components/Label" component={Label} subcomponents={{LabelCaption}} />

Note the extra pair of braces. what version are you on? possibly broken in 6.0-alpha since it was massively rewritten.

@Pete-Robelou
Copy link

The extra pair of braces didn't work. I'm on 5.3.18.

I assume this is correct for the props table?

<Props of={Label} />

@shilman
Copy link
Member

shilman commented Apr 22, 2020

Yes or tabs with:

<Props components={{Label, LabelCaption}} />

@Pete-Robelou
Copy link

👍 That works.

I've removed subcomponents={{LabelCaption}} from <Meta> as this doesn't appear to have an impact.

@trumbitta
Copy link

Hi, it seems subcomponents is not a valid prop of Meta?

https://github.com/storybookjs/storybook/blob/next/addons/docs/src/blocks/Meta.tsx

@shilman
Copy link
Member

shilman commented Aug 9, 2020

This is fixed in 6.0, closing. Either:

import { Meta, ArgsTable } from '@storybook/addon-docs/blocks';

<Meta component={Foo} subcomponents={{ Bar: Baz }} />

OR:

<ArgsTable components={{ A: Apple, B: Banana, Cherry }} />

@bnannier
Copy link

bnannier commented Oct 4, 2021

Easy way to do this is to define the child's display Name
Component.SubComponent.jsx

const SubComponent = ({children}) => {
    return (<div>{children}</div>)
}
export default SubComponent;

Component.jsx

import SubComponent from './SubComponent';

const Component = ({children}) => {
    return (<div>{children}</div>)
}

SubComponent.displayName = "Component.SubComponent"; {/* This now changes the displayname from SubComponent to Component.SubComponent */}
Component.SubComponent = SubComponent;
export default Component;

Component.stories.jsx

import Component from './Component';

export default {
  title: 'Example/Component',
  component: Component,
  subcomponents: { 'Component.SubComponent' : Component.SubComponent },
};

const Template = (args) => (
  <Component {...args}>
    <Component.SubComponent>shit</Component.SubComponent>
  </Component>
);

export const SomeStory = Template.bind({});
SomeStory.args = {
  collapsed: false,
};

@norcino
Copy link

norcino commented Nov 2, 2021

@bnannierI love the innerText of the SubComponent..

I am using this code:

import React from "react";
import Accordion from "./Accordion";
import documentation from "./Accordion.docs.json";
import design from "./Accordion.fig.json"; // This just contains { }
import './Accordion.scss';

const docs = {
    title: "Components/Accordion",
    component: Accordion,
    subcomponents: {
      'Accordion.Item': Accordion.Item,
      'Accordion.Header': Accordion.Header,
      'Accordion.Body': Accordion.Body
    },
    parameters: { },
    argTypes: {...documentation, design}
  };
export default docs;

const Template = (args) => {
    return (
      <Accordion  {...args} defaultActiveKey="0">
          <Accordion.Item eventKey="0">
              <Accordion.Header>Accordion Item #1</Accordion.Header>
              <Accordion.Body>
                  Lorem ipsum.
              </Accordion.Body>
          </Accordion.Item>
          <Accordion.Item eventKey="1">
              <Accordion.Header>Accordion Item #2</Accordion.Header>
              <Accordion.Body>
                  Lorem ipsum.
              </Accordion.Body>
          </Accordion.Item>
      </Accordion>
  );
};

export const Default = Template.bind({});

and this renders (I think) correctly, or at least it is showing what I wanted:

image

The Accordion.doc.json file just contains the definition fo the argTypes:

{
    "activeKey": {
        "type": {
            "name": "string"
        },
        "description": "<p>The current active key that corresponds to the currently expanded card</p>"
    },
    "defaultActiveKey": {
        "type": {
            "name": "string"
        },
        "description": "<p>The default active key that is expanded on start</p>"
    },
    "flush": {
        "type": {
            "name": "boolean"
        },
        "defaultValue": false,
        "description": "<p>Renders accordion edge-to-edge with its parent container</p>"
    }
}

What I really fail now to figure out, is where am I supposed to get the argTypes for the sub components to render the controls correctly, can you give me any clue?

Edit: forgot to mention, I did not use the displayName property, I didn't set anything for the purpose.

@RodrigoTomeES
Copy link

Easy way to do this is to define the child's display Name Component.SubComponent.jsx

const SubComponent = ({children}) => {
    return (<div>{children}</div>)
}
export default SubComponent;

Component.jsx

import SubComponent from './SubComponent';

const Component = ({children}) => {
    return (<div>{children}</div>)
}

SubComponent.displayName = "Component.SubComponent"; {/* This now changes the displayname from SubComponent to Component.SubComponent */}
Component.SubComponent = SubComponent;
export default Component;

Component.stories.jsx

import Component from './Component';

export default {
  title: 'Example/Component',
  component: Component,
  subcomponents: { 'Component.SubComponent' : Component.SubComponent },
};

const Template = (args) => (
  <Component {...args}>
    <Component.SubComponent>shit</Component.SubComponent>
  </Component>
);

export const SomeStory = Template.bind({});
SomeStory.args = {
  collapsed: false,
};

Hi,

I think is a better approach set the display name in the subcomponent because you don't need to extract it in the parent component:

const SubComponent = ({children}) => {
    return (<div>{children}</div>)
}
SubComponent.displayName = "Component.SubComponent"; {/* This now changes the displayname from 
export default SubComponent;

@clukhei
Copy link

clukhei commented Jun 14, 2022

@bnannierI love the innerText of the SubComponent..

I am using this code:

import React from "react";
import Accordion from "./Accordion";
import documentation from "./Accordion.docs.json";
import design from "./Accordion.fig.json"; // This just contains { }
import './Accordion.scss';

const docs = {
    title: "Components/Accordion",
    component: Accordion,
    subcomponents: {
      'Accordion.Item': Accordion.Item,
      'Accordion.Header': Accordion.Header,
      'Accordion.Body': Accordion.Body
    },
    parameters: { },
    argTypes: {...documentation, design}
  };
export default docs;

const Template = (args) => {
    return (
      <Accordion  {...args} defaultActiveKey="0">
          <Accordion.Item eventKey="0">
              <Accordion.Header>Accordion Item #1</Accordion.Header>
              <Accordion.Body>
                  Lorem ipsum.
              </Accordion.Body>
          </Accordion.Item>
          <Accordion.Item eventKey="1">
              <Accordion.Header>Accordion Item #2</Accordion.Header>
              <Accordion.Body>
                  Lorem ipsum.
              </Accordion.Body>
          </Accordion.Item>
      </Accordion>
  );
};

export const Default = Template.bind({});

and this renders (I think) correctly, or at least it is showing what I wanted:

image

The Accordion.doc.json file just contains the definition fo the argTypes:

{
    "activeKey": {
        "type": {
            "name": "string"
        },
        "description": "<p>The current active key that corresponds to the currently expanded card</p>"
    },
    "defaultActiveKey": {
        "type": {
            "name": "string"
        },
        "description": "<p>The default active key that is expanded on start</p>"
    },
    "flush": {
        "type": {
            "name": "boolean"
        },
        "defaultValue": false,
        "description": "<p>Renders accordion edge-to-edge with its parent container</p>"
    }
}

What I really fail now to figure out, is where am I supposed to get the argTypes for the sub components to render the controls correctly, can you give me any clue?

Edit: forgot to mention, I did not use the displayName property, I didn't set anything for the purpose.

@norcino thanks for the guide! did u manage to load descriptions for the subcomponents ?

<Meta title="Components/Footer" component={Footer} 
subcomponents={{ 
  'Footer.Top' : Footer.Top,
  'Footer.Top.Header': Footer.Top.Header,
  'Footer.Top.ItemGroup': Footer.Top.ItemGroup,
  'Footer.Top.Item': Footer.Top.ItemGroup
 }}
argTypes={{
  bsPrefix: {
    description: 'Override the default bootstrap prefix',
  },
  as: {
    description : 'Set a custom element for this component'
  },
  headerTitle: {
    description: 'THis is not showing at the right place'
  }
}}/>

I loaded the subcomponents, but could not find a way to fill in the descriptions of the subcomponents table.
Screenshot 2022-06-14 at 1 54 36 PM

@norcino
Copy link

norcino commented Oct 7, 2022

@clukhei sorry I didn't get the notification or I missed it.
I use stories in JSX format, so I don't know why you are not seeing the descriptions.
But how did you manage to load the argTypes for the other sub components?
That is still something I can't do.

@basickarl
Copy link

@blind76 This is already supported, e.g.

https://github.com/storybookjs/storybook/blob/next/examples/official-storybook/stories/addon-docs/subcomponents.stories.js

Hey man, 404 page! Was it moved somewhere?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants