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

[Angular] Addon-controls: inference issues with enum props #12531

Closed
jordanfonseca-iad opened this issue Sep 21, 2020 · 12 comments
Closed

[Angular] Addon-controls: inference issues with enum props #12531

jordanfonseca-iad opened this issue Sep 21, 2020 · 12 comments

Comments

@jordanfonseca-iad
Copy link

jordanfonseca-iad commented Sep 21, 2020

I am not sure that my issue is related to this but I've got this type of behaviour in "@storybook/vue": "^6.0.21":

  1. I'm importing enum in the story
  2. Using it in Default.args
  3. Control is appearing as textfield

Originally posted by @justice47 in #12007 (comment)


I'm experiencing the same problem with Angular.
Storybook version : 6.0.21
Angular version : 8.2.14

Example given with an avatar component :

// avatar.stories.ts

export default {
  title: 'Components/Avatar',
  component: AvatarComponent,
  decorators: [
    moduleMetadata({
      imports: [AvatarModule]
    })
  ]
};

const Template: Story<AvatarComponent> = (args: AvatarComponent) => ({
  component: AvatarComponent,
  props: args
});

export const Small = Template.bind({});
Small.args = {
  size: AvatarSize.SMALL
};
// avatar.component.ts

@Component({
  // ...
})
export class AvatarComponent {
  @Input() size?: AvatarSize;
  // ...
}

The size control is displayed as a textfield and not a select.

@jordanfonseca-iad
Copy link
Author

Thanks @shilman, I've obviously read it before posting this issue 😄
I'm currently using manual controls with argTypes but I would have liked understand why enums aren't auto-generated as select inputs. Is it an issue or a missing feature ? Sorry if I've missed something on enums support in the README.

If my type is not an enum but an union type, it works :

export class AvatarComponent {
  @Input() size?: 'small' | 'medium' | 'large'; // Auto-generated in select input
}
export class AvatarComponent {
  @Input() size?: AvatarSize; // Auto-generated in text input
}

Thanks for your answer and have a good day !

@shilman
Copy link
Member

shilman commented Sep 25, 2020

We're using vue-docgen-api to generate this, so maybe @elevatebart knows the answer?

@lachieh
Copy link
Contributor

lachieh commented Oct 1, 2020

First of all, I really appreciate the efforts of the Storybook team! The Controls addon is a fantastic addition!

I came across this issue also so I did some digging. This is the relevant function as far as I can tell.

const extractEnumValues = (compodocType: any) => {
if (typeof compodocType !== 'string' || compodocType.indexOf('|') === -1) {
return null;
}
try {
return compodocType.split('|').map((value) => JSON.parse(value));
} catch (e) {
return null;
}
};

The code below doesn't generate a select input control because the extractEnumValues function only checks if the type it is dealing with is a union type (by checking for a pipe character). It can't infer the enum type from just the type name because that data is stored elsewhere in the compodoc output file (see bottom).

export class AvatarComponent {
  @Input() size?: AvatarSize; // Auto-generated in text input
}

enum AvatarSize {
  SMALL = 'SMALL',
  MEDIUM = 'MEDIUM',
  LARGE = 'LARGE',
}

The same problem exists when using a type alias like this:

export class AvatarComponent {
  @Input() size?: AvatarSize;
}

type AvatarSize = 'small' | 'medium' | 'large'

While compodoc does generate the data for enums under miscellaneous.enumerations, it doesn't store this information in the same object as the component definition meaning it isn't readily available while looping over each component and directive. I'm not sure where to go from here, but the snippet below is an example of the resulting json from compodoc if someone wants to take a stab at investigating further.

{
  // ...
    "miscellaneous": {
      // ...
        "enumerations": [
            // ...
            {
              "name": "AvatarSize",
              "childs": [
                  {
                      "name": "SMALL"
                  },
                  {
                      "name": "MEDIUM"
                  },
                  {
                      "name": "LARGE"
                  }
              ],
              "ctype": "miscellaneous",
              "subtype": "enum",
              "description": "",
              "file": "src/avatar/avatar.component.ts"
            },
        ]
    }
}

@shilman
Copy link
Member

shilman commented Oct 1, 2020

@lachieh thanks for the research on this. should be pretty easy to add this to extractArgTypes for angular. if anybody wants to take this, I'd be happy to help guide.

@lachieh
Copy link
Contributor

lachieh commented Oct 1, 2020

I would be interested! Point me in the right direction and I'll get started.

@lachieh
Copy link
Contributor

lachieh commented Oct 2, 2020

@shilman I notice there's a getCompdocJson function. Would I use that to get the miscellaneous key and look for the type that matches?

@shilman
Copy link
Member

shilman commented Oct 3, 2020

Sorry, missed your previous comment. Relevant code is here:

https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/angular/compodoc.ts#L155

Please be sure to add a test case to examples/angular-cli and you can test it out as you develop using the instructions provided in CONTRIBUTING.md. LMK if that makes sense!

@lachieh
Copy link
Contributor

lachieh commented Oct 5, 2020

Thanks, @shilman! PR opened here: #12665

@graup
Copy link
Contributor

graup commented Oct 6, 2020

This isn't just an angular issue, I'm seeing the same on React. And the OP talked about vue. I assume it's for the exact same reason there.

@lachieh
Copy link
Contributor

lachieh commented Oct 7, 2020

One thing to note for my PR is that even though I have been able extract the values from an enum type, the only version of enums that work are String Enums. When I got the value to assign to the dropdown control, even though the enum had a name, the control input displays the number value (0, 1, 2, etc).

It's possible that a future iteration of docs and/or controls needs to support enums that have a value and a label, instead of just a list of values.

@shilman
Copy link
Member

shilman commented Dec 1, 2020

Gadzooks!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.2.0-alpha.0 containing PR #12665 that references this issue. Upgrade today to the @next NPM tag to try it out!

npx sb upgrade --prerelease

Closing this issue. Please re-open if you think there's still more to do.

@shilman shilman closed this as completed Dec 1, 2020
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

4 participants