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

[Bug]: Multiple mapped args return array of labels, not args #22042

Open
drunkenvalley opened this issue Apr 12, 2023 · 2 comments
Open

[Bug]: Multiple mapped args return array of labels, not args #22042

drunkenvalley opened this issue Apr 12, 2023 · 2 comments

Comments

@drunkenvalley
Copy link

drunkenvalley commented Apr 12, 2023

Describe the bug

Using a multi-select control such as multi-select, check, etc, will cause the mapped argument to only return an array containing the labels of the arguments.

For example, using the example on Dealing with complex values we have this story:

// Button.stories.ts|tsx

// Replace your-framework with the name of your framework
import type { Meta } from '@storybook/your-framework';

import { Button } from './Button';

import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';

const arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };

const meta: Meta<typeof Button> = {
  /* 👇 The title prop is optional.
   * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
   * to learn how to generate automatic titles
   */
  title: 'Button',
  component: Button,
  argTypes: {
    arrow: {
      options: Object.keys(arrows), // An array of serializable values
      mapping: arrows, // Maps serializable option values to complex arg values
      control: {
        type: 'select', // Type 'select' is automatically inferred when 'options' is defined
        labels: {
          // 'labels' maps option values to string labels
          ArrowUp: 'Up',
          ArrowDown: 'Down',
          ArrowLeft: 'Left',
          ArrowRight: 'Right',
        },
      },
    },
  },
};

export default meta;

In the given example with the control's type set to select, selecting an item returns that item. For example, selecting "Up" will return ArrowUp.

However, if we replace that control's type to multi-select, selecting an additional item will return an array of labels instead, not an array of the selected items. For example, selecting "Up" and "Down" will return ["Up", "Down"] instead. (Or it should. I only tested with implicit labels. It may return ["ArrowUp", "ArrowDown"] instead.)

Current behavior:

When selecting one item it will return the object containing that item. When selecting multiple it returns an array of the options' labels.

Expected behavior:

When selecting one item it should return the object containing that item. When selecting multiple it should return an array or object containing all selected values.

Alternatively, when using controls allowing selecting multiple it should always return an array containing the selected objects.

To Reproduce

See reproduction stackblitz here: https://stackblitz.com/edit/github-yw4xwr?file=src/stories/List.stories.ts

// List.vue

<template>
  <ul>
    <li v-for="item in $slots.default" :key="item.key">
      <VNodes :vnode="item" />
    </li>
  </ul>
</template>
<script>
export default {
  components: {
    VNodes: {
      functional: true,
      render: (h, ctx) => ctx.props.vnode,
    },
  },
};
</script>
// ListTemplate.vue

<template>
  <List>
    <a v-for="{ slot, ...item } in parsedItems" :key="slot" v-bind="item">
      {{ slot }}
    </a>
    <div>
      Raw input from `items`: <br />
      <code>
        {{ items }}
      </code>
    </div>
  </List>
</template>
<script>
import List from './List.vue';

export default {
  components: {
    List,
  },
  props: {
    items: {
      type: [Array | Object],
      required: false,
      default: () => ({}),
    },
  },
  computed: {
    parsedItems() {
      if (Array.isArray(this.items)) {
        // since we currently receive strings with multiple it would break the template;
        // this is a patch to not disturb the reproduction
        const fixedStrings = this.items.map((item) => {
          if (typeof item === 'string') {
            return {
              href: 'https://fakedurl.com',
              slot: item,
            };
          }
          return item;
        });

        return fixedStrings;
      }
      if (Object.keys(this.items)) {
        return [this.items];
      }
      return [];
    },
  },
};
</script>
// List.stories.ts

import type { Meta, StoryObj } from '@storybook/vue';
import { StoryFn } from '@storybook/vue';

import Vue from 'vue';
// @ts-ignore
import Component from './List.vue';
// @ts-ignore
import Template from './ListTemplate.vue';

const items = {
  'Annual Report 2017': {
    slot: 'Annual Report 2017',
    href: 'https://example.com',
  },
  'Annual Report 2018': {
    slot: 'Annual Report 2018',
    href: 'https://example.com',
  },
};

const meta: Meta<typeof Component> = {
  title: 'List',
  component: Component,
};
export default meta;

const render: StoryFn = (args, { argTypes }) =>
  Vue.extend({
    props: Object.keys(argTypes),
    components: { Template },
    template: `<Template v-bind="$props"></Template>`,
  });

export const PageList: StoryObj<typeof Component> = {
  render,
  argTypes: {
    // default slot disabled here to avoid keyword error
    default: {
      table: {
        disable: true,
      },
    },
    items: {
      name: 'default',
      control: 'check',
      options: Object.keys(items),
      mapping: items,
      table: {
        category: 'slots',
      },
    },
  },
  args: {
    items: ['Annual Report 2017'],
    margin: true,
  },
};

System

Environment Info:

  System:
    OS: Windows 10 10.0.19045
    CPU: (32) x64 AMD Ryzen 9 7950X 16-Core Processor              
  Binaries:
    Node: 16.18.1 - C:\Program Files\nodejs\node.EXE
    npm: 8.19.2 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromium (112.0.1722.39)      
  npmPackages:
    @storybook/addon-essentials: ^7.1.0-alpha.1 => 7.1.0-alpha.1   
    @storybook/addon-interactions: ^7.1.0-alpha.1 => 7.1.0-alpha.1 
    @storybook/addon-links: ^7.1.0-alpha.1 => 7.1.0-alpha.1        
    @storybook/blocks: ^7.1.0-alpha.1 => 7.1.0-alpha.1 
    @storybook/testing-library: ^0.0.14-next.2 => 0.0.14-next.2    
    @storybook/vue: ^7.1.0-alpha.1 => 7.1.0-alpha.1 
    @storybook/vue-vite: ^7.1.0-alpha.1 => 7.1.0-alpha.1 

Additional context

Reproduction should show as following.

No items

image

One item

image

Two items

image

Updated System info to result from reproduction repo.

@drunkenvalley drunkenvalley changed the title [Bug]: Multiple mapped args [Bug]: Multiple mapped args return array of labels, not args Apr 12, 2023
@shilman
Copy link
Member

shilman commented Apr 27, 2023

ZOMG!! I just released https://github.com/storybookjs/storybook/releases/tag/v7.1.0-alpha.10 containing PR #22169 that references this issue. Upgrade today to the @future NPM tag to try it out!

npx sb@next upgrade --tag future

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

@shilman
Copy link
Member

shilman commented May 3, 2023

ZOMG!! I just released https://github.com/storybookjs/storybook/releases/tag/v7.0.8 containing PR #22169 that references this issue. Upgrade today to the @latest NPM tag to try it out!

npx sb@latest upgrade

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

2 participants