Skip to content

Commit

Permalink
Merge pull request #14394 from stevensacks/fix/ArgControl-cleanup
Browse files Browse the repository at this point in the history
Controls: Clean up arg unboxing and switch statements
  • Loading branch information
shilman committed Jul 19, 2021
2 parents 3ade20d + 4400681 commit 94dcdbb
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 46 deletions.
57 changes: 24 additions & 33 deletions lib/components/src/blocks/ArgsTable/ArgControl.tsx
Expand Up @@ -18,22 +18,39 @@ export interface ArgControlProps {
updateArgs: (args: Args) => void;
}

const Controls: Record<string, FC> = {
array: ObjectControl,
object: ObjectControl,
boolean: BooleanControl,
color: ColorControl,
date: DateControl,
number: NumberControl,
check: OptionsControl,
'inline-check': OptionsControl,
radio: OptionsControl,
'inline-radio': OptionsControl,
select: OptionsControl,
'multi-select': OptionsControl,
range: RangeControl,
text: TextControl,
file: FilesControl,
};

const NoControl = () => <>-</>;

export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs }) => {
const { key, control } = row;

const [isFocused, setFocused] = useState(false);
// box because arg can be a fn (e.g. actions) and useState calls fn's
const [boxedValue, setBoxedValue] = useState({ value: arg });
const [value, setValue] = useState(() => arg);

useEffect(() => {
if (!isFocused) setBoxedValue({ value: arg });
if (!isFocused) setValue(arg);
}, [isFocused, arg]);

const onChange = useCallback(
(argVal: any) => {
setBoxedValue({ value: argVal });
setValue(argVal);
updateArgs({ [key]: argVal });
return argVal;
},
Expand All @@ -47,33 +64,7 @@ export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs }) => {

// row.name is a display name and not a suitable DOM input id or name - i might contain whitespace etc.
// row.key is a hash key and therefore a much safer choice
const props = { name: key, argType: row, value: boxedValue.value, onChange, onBlur, onFocus };
switch (control.type) {
case 'array':
case 'object':
return <ObjectControl {...props} {...control} />;
case 'boolean':
return <BooleanControl {...props} {...control} />;
case 'color':
return <ColorControl {...props} {...control} />;
case 'date':
return <DateControl {...props} {...control} />;
case 'number':
return <NumberControl {...props} {...control} />;
case 'check':
case 'inline-check':
case 'radio':
case 'inline-radio':
case 'select':
case 'multi-select':
return <OptionsControl {...props} {...control} controlType={control.type} />;
case 'range':
return <RangeControl {...props} {...control} />;
case 'text':
return <TextControl {...props} {...control} />;
case 'file':
return <FilesControl {...props} {...control} />;
default:
return <NoControl />;
}
const props = { name: key, argType: row, value, onChange, onBlur, onFocus };
const Control = Controls[control.type] || NoControl;
return <Control {...props} {...control} controlType={control.type} />;
};
34 changes: 21 additions & 13 deletions lib/components/src/controls/options/Options.tsx
Expand Up @@ -28,28 +28,36 @@ const normalizeOptions = (options: Options, labels?: Record<any, string>) => {
return options;
};

const Controls: Record<string, FC> = {
check: CheckboxControl,
'inline-check': CheckboxControl,
radio: RadioControl,
'inline-radio': RadioControl,
select: SelectControl,
'multi-select': SelectControl,
};

export type OptionsProps = ControlProps<OptionsSelection> & OptionsConfig;
export const OptionsControl: FC<OptionsProps> = (props) => {
const { type = 'select', options, labels, argType } = props;
const normalized = { ...props, options: normalizeOptions(options || argType.options, labels) };
const normalized = {
...props,
options: normalizeOptions(options || argType.options, labels),
isInline: type.includes('inline'),
isMulti: type.includes('multi'),
};

if (options) {
once.warn(dedent`
'control.options' is deprecated and will be removed in Storybook 7.0. Define 'options' directly on the argType instead, and use 'control.labels' for custom labels.
More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-controloptions
`);
}
switch (type) {
case 'check':
case 'inline-check':
return <CheckboxControl {...normalized} isInline={type === 'inline-check'} />;
case 'radio':
case 'inline-radio':
return <RadioControl {...normalized} isInline={type === 'inline-radio'} />;
case 'select':
case 'multi-select':
return <SelectControl {...normalized} isMulti={type === 'multi-select'} />;
default:
throw new Error(`Unknown options type: ${type}`);

const Control = Controls[type];
if (Control) {
return <Control {...normalized} />;
}
throw new Error(`Unknown options type: ${type}`);
};

0 comments on commit 94dcdbb

Please sign in to comment.