Skip to content

Commit

Permalink
Merge pull request #14976 from storybookjs/14752-fix-controls-without…
Browse files Browse the repository at this point in the history
…-options

Controls: Fix controls without options and add warning
  • Loading branch information
shilman authored May 18, 2021
2 parents e8e0cba + 231b114 commit cadd381
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,8 @@ FilteredWithExcludeRegex.parameters = {
exclude: /hello*/,
},
};

// https://github.com/storybookjs/storybook/issues/14752
export const MissingRadioOptions = Template.bind({});
MissingRadioOptions.argTypes = { invalidRadio: { control: 'radio' } };
MissingRadioOptions.args = { invalidRadio: 'someValue' };
6 changes: 6 additions & 0 deletions lib/components/src/controls/options/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC, ChangeEvent, useState, Fragment } from 'react';
import { styled } from '@storybook/theming';
import { logger } from '@storybook/client-logger';
import { ControlProps, OptionsMultiSelection, NormalizedOptionsConfig } from '../types';
import { selectedKeys, selectedValues } from './helpers';

Expand Down Expand Up @@ -48,6 +49,11 @@ export const CheckboxControl: FC<CheckboxProps> = ({
onChange,
isInline,
}) => {
if (!options) {
logger.warn(`Checkbox with no options: ${name}`);
return <>-</>;
}

const initial = selectedKeys(value, options);
const [selected, setSelected] = useState(initial);

Expand Down
5 changes: 5 additions & 0 deletions lib/components/src/controls/options/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC } from 'react';
import { styled } from '@storybook/theming';
import { logger } from '@storybook/client-logger';
import { ControlProps, OptionsSingleSelection, NormalizedOptionsConfig } from '../types';
import { selectedKey } from './helpers';

Expand Down Expand Up @@ -48,6 +49,10 @@ const Label = styled.label({
type RadioConfig = NormalizedOptionsConfig & { isInline: boolean };
type RadioProps = ControlProps<OptionsSingleSelection> & RadioConfig;
export const RadioControl: FC<RadioProps> = ({ name, options, value, onChange, isInline }) => {
if (!options) {
logger.warn(`Radio with no options: ${name}`);
return <>-</>;
}
const selection = selectedKey(value, options);
return (
<Wrapper isInline={isInline}>
Expand Down
12 changes: 10 additions & 2 deletions lib/components/src/controls/options/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC, ChangeEvent } from 'react';
import { styled, CSSObject } from '@storybook/theming';
import { logger } from '@storybook/client-logger';
import { ControlProps, OptionsSelection, NormalizedOptionsConfig } from '../types';
import { selectedKey, selectedKeys, selectedValues } from './helpers';
import { Icons } from '../../icon/icon';
Expand Down Expand Up @@ -129,6 +130,13 @@ const MultiSelect: FC<SelectProps> = ({ name, value, options, onChange }) => {
);
};

export const SelectControl: FC<SelectProps> = (props) =>
export const SelectControl: FC<SelectProps> = (props) => {
const { name, options } = props;
if (!options) {
logger.warn(`Select with no options: ${name}`);
return <>-</>;
}

// eslint-disable-next-line react/destructuring-assignment
props.isMulti ? <MultiSelect {...props} /> : <SingleSelect {...props} />;
return props.isMulti ? <MultiSelect {...props} /> : <SingleSelect {...props} />;
};
6 changes: 3 additions & 3 deletions lib/components/src/controls/options/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { OptionsObject } from '../types';

export const selectedKey = (value: any, options: OptionsObject) => {
const entry = Object.entries(options).find(([_key, val]) => val === value);
const entry = options && Object.entries(options).find(([_key, val]) => val === value);
return entry ? entry[0] : undefined;
};

export const selectedKeys = (value: any[], options: OptionsObject) =>
value
value && options
? Object.entries(options)
.filter((entry) => value.includes(entry[1]))
.map((entry) => entry[0])
: [];

export const selectedValues = (keys: string[], options: OptionsObject) =>
keys.map((key) => options[key]);
keys && options && keys.map((key) => options[key]);

0 comments on commit cadd381

Please sign in to comment.