how to define a complex data type in Storybook CSF argTypes

Viewed 5618

Let's say I have a table component and I want to specify the structure of the columnList property in CSF notation. The component has an argument/property which takes a list of column definitions.

For example:

[
   {name: "id", label: "Id", sortable: true}, 
   {name: "firstName", label: "Firstname", sortable: true},
   {name: "lastName", label: "Lastname", sortable: true},
]

Then how should the story be defined?

export default {
  title: 'Table',
  component: NgxTableComponent,
  argTypes: {
    title: {
      type: {name: 'string', required: false}
    },
    columnList: {
      type: {name: ???, required: true}
    }
  }
};

What should the ??? be?

In JSON-Schema notation this would be:

{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
       "name": "string",
       "label": "string",
       "sortable" "boolean"
     }
  }
}

Can this be achieved in CSF?

Is it then possible to have (via add-on?) a Control in Storybook to define this columnList?

2 Answers

Since I haven't found documentation regarding how to define the array objects structure using ArgTypes in Angular, I tried this approach which was the only one it seemed to work. For objects inside an array, inferred types work fairly well whereas ArgTypes should be removed to avoid the display of [object Object],[object Object] in Controls tab. So an alternative would be to define a typed constant with default values and assign it to the args as follows:

// my-table.stories.ts

interface ColumnListItemInterface { name: string, required: boolean }
interface TableTitleInterface { name: string, required: boolean }

const myList: ColumnListItemInterface[] = [
    {
        name: 'item name',
        required: true,
    },
    {
        name: 'second name',
        required: false,
    },
];
const myTitle: TableTitleInterface = {
    name: 'my title', required: false
};

export default {
    title: 'Table',
    component: NgxTableComponent,
    args: {
        title: myTitle,
        columnList: myList,
    },
}

export const Default = (model: { title: TableTitleInterface, columnList: ColumnListItemInterface[] }) => 
{
    return {
        template: `
            <my-selector [title]="model.title" [list]="model.list"></my-selector>
        `,
        props: { model },
        args: { model },
    };
};

With help from Typescript and setting the initial args like above, you should get the Controls in Storybook display the array for columnListInput in the shape of the following string and be able to edit it:

[{"name":"item name","required":"true"},{"name":"second name","required":"false"}]

This worked for me:

columnList: { table: { expanded: true } }

Then, in Controls you get the whole array of objects printed, and you can "play there" changing its values.

Related