From 130af10d06c7de8b578cee451716575e276adf25 Mon Sep 17 00:00:00 2001 From: Emilio Martinez Date: Thu, 11 Jul 2019 16:18:14 -0700 Subject: [PATCH] Addon-knobs: organize type definitions a bit --- addons/knobs/src/KnobManager.ts | 3 +- addons/knobs/src/KnobStore.ts | 45 +--------------------- addons/knobs/src/components/Panel.tsx | 17 +++----- addons/knobs/src/components/PropForm.tsx | 4 +- addons/knobs/src/components/types/index.ts | 15 +++++++- addons/knobs/src/index.ts | 2 +- addons/knobs/src/type-defs.ts | 45 ++++++++++++++++++++++ 7 files changed, 71 insertions(+), 60 deletions(-) create mode 100644 addons/knobs/src/type-defs.ts diff --git a/addons/knobs/src/KnobManager.ts b/addons/knobs/src/KnobManager.ts index 82535a975963..fe875efd61ea 100644 --- a/addons/knobs/src/KnobManager.ts +++ b/addons/knobs/src/KnobManager.ts @@ -6,7 +6,8 @@ import { getQueryParams } from '@storybook/client-api'; // eslint-disable-next-line import/no-extraneous-dependencies import { Channel } from '@storybook/channels'; -import KnobStore, { Knob, KnobStoreKnob, KnobType } from './KnobStore'; +import KnobStore, { KnobStoreKnob } from './KnobStore'; +import { Knob, KnobType } from './type-defs'; import { SET } from './shared'; import { deserializers } from './converters'; diff --git a/addons/knobs/src/KnobStore.ts b/addons/knobs/src/KnobStore.ts index 1129002b4bed..31b4207e8edb 100644 --- a/addons/knobs/src/KnobStore.ts +++ b/addons/knobs/src/KnobStore.ts @@ -1,50 +1,7 @@ -import Types, { - TextTypeKnob, - NumberTypeKnob, - ColorTypeKnob, - BooleanTypeKnob, - ObjectTypeKnob, - SelectTypeKnob, - RadiosTypeKnob, - ArrayTypeKnob, - DateTypeKnob, - ButtonTypeOnClickProp, - FileTypeKnob, - OptionsTypeKnob, -} from './components/types'; +import { Knob } from './type-defs'; type Callback = () => any; -export type KnobType = keyof typeof Types; - -type KnobPlus = K & { type: T; groupId?: string }; - -export type Knob = T extends 'text' - ? KnobPlus> - : T extends 'boolean' - ? KnobPlus> - : T extends 'number' - ? KnobPlus> - : T extends 'color' - ? KnobPlus> - : T extends 'object' - ? KnobPlus, 'value'>> - : T extends 'select' - ? KnobPlus & { selectV2: true }> - : T extends 'radios' - ? KnobPlus> - : T extends 'array' - ? KnobPlus> - : T extends 'date' - ? KnobPlus> - : T extends 'files' - ? KnobPlus> - : T extends 'button' - ? KnobPlus - : T extends 'options' - ? KnobPlus, 'options' | 'value' | 'optionsObj'>> - : never; - export type KnobStoreKnob = Knob & { name: string; label: string; diff --git a/addons/knobs/src/components/Panel.tsx b/addons/knobs/src/components/Panel.tsx index de5a3ceababc..4154e6359992 100644 --- a/addons/knobs/src/components/Panel.tsx +++ b/addons/knobs/src/components/Panel.tsx @@ -1,4 +1,4 @@ -import React, { PureComponent, Fragment, ComponentType } from 'react'; +import React, { PureComponent, Fragment } from 'react'; import PropTypes from 'prop-types'; import qs from 'qs'; import { document } from 'global'; @@ -16,7 +16,7 @@ import { } from '@storybook/components'; import { RESET, SET, CHANGE, SET_OPTIONS, CLICK } from '../shared'; -import Types from './types'; +import { getKnobControl } from './types'; import PropForm from './PropForm'; import { KnobStoreKnob } from '../KnobStore'; @@ -58,11 +58,6 @@ interface KnobPanelOptions { timestamps?: boolean; } -type KnobControlType = ComponentType & { - serialize: (v: any) => any; - deserialize: (v: any) => any; -}; - export default class KnobPanel extends PureComponent { static propTypes = { active: PropTypes.bool.isRequired, @@ -133,9 +128,9 @@ export default class KnobPanel extends PureComponent { // If the knob value present in url if (urlValue !== undefined) { - const value = (Types[knob.type] as KnobControlType).deserialize(urlValue); + const value = getKnobControl(knob.type).deserialize(urlValue); knob.value = value; - queryParams[`knob-${name}`] = (Types[knob.type] as KnobControlType).serialize(value); + queryParams[`knob-${name}`] = getKnobControl(knob.type).serialize(value); api.emit(CHANGE, knob); } @@ -161,7 +156,7 @@ export default class KnobPanel extends PureComponent { const { knobs } = this.state; Object.entries(knobs).forEach(([name, knob]) => { - query[`knob-${name}`] = (Types[knob.type] as KnobControlType).serialize(knob.value); + query[`knob-${name}`] = getKnobControl(knob.type).serialize(knob.value); }); copy(`${location.origin + location.pathname}?${qs.stringify(query, { encode: false })}`); @@ -193,7 +188,7 @@ export default class KnobPanel extends PureComponent { Object.keys(newKnobs).forEach(n => { const knob = newKnobs[n]; - queryParams[`knob-${n}`] = (Types[knob.type] as KnobControlType).serialize(knob.value); + queryParams[`knob-${n}`] = getKnobControl(knob.type).serialize(knob.value); }); api.setQueryParams(queryParams); diff --git a/addons/knobs/src/components/PropForm.tsx b/addons/knobs/src/components/PropForm.tsx index 5b4c381151f9..3a345a67f0bf 100644 --- a/addons/knobs/src/components/PropForm.tsx +++ b/addons/knobs/src/components/PropForm.tsx @@ -2,7 +2,7 @@ import React, { Component, WeakValidationMap, ComponentType, Requireable } from import PropTypes from 'prop-types'; import { Form } from '@storybook/components'; -import TypeMap from './types'; +import { getKnobControl } from './types'; import { KnobStoreKnob } from '../KnobStore'; interface PropFormProps { @@ -48,7 +48,7 @@ export default class PropForm extends Component {
{knobs.map(knob => { const changeHandler = this.makeChangeHandler(knob.name, knob.type); - const InputType: ComponentType = TypeMap[knob.type] || InvalidType; + const InputType: ComponentType = getKnobControl(knob.type) || InvalidType; return ( diff --git a/addons/knobs/src/components/types/index.ts b/addons/knobs/src/components/types/index.ts index a4a727445b3d..1a25315f8d0b 100644 --- a/addons/knobs/src/components/types/index.ts +++ b/addons/knobs/src/components/types/index.ts @@ -1,3 +1,5 @@ +import { ComponentType } from 'react'; + import TextType from './Text'; import NumberType from './Number'; import ColorType from './Color'; @@ -11,7 +13,7 @@ import ButtonType from './Button'; import FilesType from './Files'; import OptionsType from './Options'; -export default { +const KnobControls = { text: TextType, number: NumberType, color: ColorType, @@ -25,6 +27,17 @@ export default { files: FilesType, options: OptionsType, }; +export default KnobControls; + +export type KnobType = keyof typeof KnobControls; + +export type KnobControlType = ComponentType & { + serialize: (v: any) => any; + deserialize: (v: any) => any; +}; + +// Note: this is a utility function that helps in resolving types more orderly +export const getKnobControl = (type: KnobType): KnobControlType => KnobControls[type]; export { TextTypeKnob } from './Text'; export { NumberTypeKnob, NumberTypeKnobOptions } from './Number'; diff --git a/addons/knobs/src/index.ts b/addons/knobs/src/index.ts index f887967fa752..c7a060c5785c 100644 --- a/addons/knobs/src/index.ts +++ b/addons/knobs/src/index.ts @@ -2,7 +2,7 @@ import addons, { makeDecorator } from '@storybook/addons'; import { SET_OPTIONS } from './shared'; import { manager, registerKnobs } from './registerKnobs'; -import { Knob, KnobType } from './KnobStore'; +import { Knob, KnobType } from './type-defs'; import { NumberTypeKnobOptions, ButtonTypeOnClickProp, diff --git a/addons/knobs/src/type-defs.ts b/addons/knobs/src/type-defs.ts new file mode 100644 index 000000000000..51c76c6c2b39 --- /dev/null +++ b/addons/knobs/src/type-defs.ts @@ -0,0 +1,45 @@ +import { + TextTypeKnob, + NumberTypeKnob, + ColorTypeKnob, + BooleanTypeKnob, + ObjectTypeKnob, + SelectTypeKnob, + RadiosTypeKnob, + ArrayTypeKnob, + DateTypeKnob, + ButtonTypeOnClickProp, + FileTypeKnob, + OptionsTypeKnob, + KnobType, +} from './components/types'; + +type KnobPlus = K & { type: T; groupId?: string }; + +export type Knob = T extends 'text' + ? KnobPlus> + : T extends 'boolean' + ? KnobPlus> + : T extends 'number' + ? KnobPlus> + : T extends 'color' + ? KnobPlus> + : T extends 'object' + ? KnobPlus, 'value'>> + : T extends 'select' + ? KnobPlus & { selectV2: true }> + : T extends 'radios' + ? KnobPlus> + : T extends 'array' + ? KnobPlus> + : T extends 'date' + ? KnobPlus> + : T extends 'files' + ? KnobPlus> + : T extends 'button' + ? KnobPlus + : T extends 'options' + ? KnobPlus, 'options' | 'value' | 'optionsObj'>> + : never; + +export { KnobType };