From e42fcf0d3d5d25e1abab021c7c28a160b017387b Mon Sep 17 00:00:00 2001 From: Steven Sacks Date: Tue, 30 Mar 2021 19:28:53 +0900 Subject: [PATCH 1/2] fix(ArgControl): unbox the value to simplify the code --- lib/components/src/blocks/ArgsTable/ArgControl.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/components/src/blocks/ArgsTable/ArgControl.tsx b/lib/components/src/blocks/ArgsTable/ArgControl.tsx index 9140f96eaaf6..9ba2094b2080 100644 --- a/lib/components/src/blocks/ArgsTable/ArgControl.tsx +++ b/lib/components/src/blocks/ArgsTable/ArgControl.tsx @@ -24,16 +24,15 @@ export const ArgControl: FC = ({ 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; }, @@ -47,7 +46,7 @@ export const ArgControl: FC = ({ 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 }; + const props = { name: key, argType: row, value, onChange, onBlur, onFocus }; switch (control.type) { case 'array': case 'object': From f9518429e82eb534338dec3c751da1f5b88fa2d3 Mon Sep 17 00:00:00 2001 From: Steven Sacks Date: Tue, 30 Mar 2021 19:52:49 +0900 Subject: [PATCH 2/2] switch from case to dict for cleaner code --- .../src/blocks/ArgsTable/ArgControl.tsx | 48 ++++++++----------- .../src/controls/options/Options.tsx | 34 ++++++++----- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/components/src/blocks/ArgsTable/ArgControl.tsx b/lib/components/src/blocks/ArgsTable/ArgControl.tsx index 9ba2094b2080..eed086327b70 100644 --- a/lib/components/src/blocks/ArgsTable/ArgControl.tsx +++ b/lib/components/src/blocks/ArgsTable/ArgControl.tsx @@ -18,6 +18,24 @@ export interface ArgControlProps { updateArgs: (args: Args) => void; } +const Controls: Record = { + 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 = ({ row, arg, updateArgs }) => { @@ -47,32 +65,6 @@ export const ArgControl: FC = ({ 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, onChange, onBlur, onFocus }; - switch (control.type) { - case 'array': - case 'object': - return ; - case 'boolean': - return ; - case 'color': - return ; - case 'date': - return ; - case 'number': - return ; - case 'check': - case 'inline-check': - case 'radio': - case 'inline-radio': - case 'select': - case 'multi-select': - return ; - case 'range': - return ; - case 'text': - return ; - case 'file': - return ; - default: - return ; - } + const Control = Controls[control.type] || NoControl; + return ; }; diff --git a/lib/components/src/controls/options/Options.tsx b/lib/components/src/controls/options/Options.tsx index 9b88795c8814..26a86b4b09da 100644 --- a/lib/components/src/controls/options/Options.tsx +++ b/lib/components/src/controls/options/Options.tsx @@ -28,10 +28,25 @@ const normalizeOptions = (options: Options, labels?: Record) => { return options; }; +const Controls: Record = { + check: CheckboxControl, + 'inline-check': CheckboxControl, + radio: RadioControl, + 'inline-radio': RadioControl, + select: SelectControl, + 'multi-select': SelectControl, +}; + export type OptionsProps = ControlProps & OptionsConfig; export const OptionsControl: FC = (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. @@ -39,17 +54,10 @@ export const OptionsControl: FC = (props) => { More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-controloptions `); } - switch (type) { - case 'check': - case 'inline-check': - return ; - case 'radio': - case 'inline-radio': - return ; - case 'select': - case 'multi-select': - return ; - default: - throw new Error(`Unknown options type: ${type}`); + + const Control = Controls[type]; + if (Control) { + return ; } + throw new Error(`Unknown options type: ${type}`); };