From 171bd779092eef1b6eb490e624fcab1e109b8494 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 16 Oct 2019 12:42:58 +0200 Subject: [PATCH] Enum, Struct & Tuple as func. components (#1727) * Enum, Struct & Tuple as func. components * type.type * Fix linting * default export --- packages/react-params/src/Param/Enum.tsx | 155 +++++++++------------ packages/react-params/src/Param/Struct.tsx | 101 +++++--------- packages/react-params/src/Param/Tuple.tsx | 134 +++++++----------- 3 files changed, 152 insertions(+), 238 deletions(-) diff --git a/packages/react-params/src/Param/Enum.tsx b/packages/react-params/src/Param/Enum.tsx index 9b51bc5fa5..2d7a61a203 100644 --- a/packages/react-params/src/Param/Enum.tsx +++ b/packages/react-params/src/Param/Enum.tsx @@ -3,9 +3,9 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { TypeDef } from '@polkadot/types/types'; -import { Props, RawParam } from '../types'; +import { ParamDef, Props, RawParam } from '../types'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { Enum, createType, getTypeDef } from '@polkadot/types'; import { Dropdown } from '@polkadot/react-components'; @@ -18,103 +18,80 @@ interface Option { value?: string; } -interface State { - def: TypeDef | null; - options: Option[]; - sub: TypeDef[]; - type: string | null; -} +export default function EnumParam (props: Props): React.ReactElement { + const { className, defaultValue, isDisabled, isError, label, onChange, style, type, withLabel } = props; + const [current, setCurrent] = useState(null); + const [initialValue, setInitialValue] = useState(null); + const [{ options, subTypes }, setOptions] = useState<{ options: Option[]; subTypes: TypeDef[] }>({ options: [], subTypes: [] }); -export default class EnumParam extends React.PureComponent { - public state: State = { - def: null, - options: [], - sub: [], - type: null - }; - - public static getDerivedStateFromProps ({ type: { type } }: Props, prevState: State): State | null { - if (prevState.type === type) { - return null; - } - - const rawType = createType(type as any).toRawType(); + useEffect((): void => { + const rawType = createType(type.type as any).toRawType(); const typeDef = getTypeDef(rawType); + const subTypes = typeDef.sub as TypeDef[]; - // HACK This is a quick hack to allow `Option` ... this is certainly not the right - // place for this, so we need to move it (even the detection just sucks)... also see struct - const sub = typeDef.type.startsWith('Option<') - ? (typeDef.sub as TypeDef).sub as TypeDef[] - : typeDef.sub as TypeDef[]; - - return { - def: prevState.def || sub[0], - options: sub.map(({ name }): Option => ({ + setOptions({ + options: subTypes.map(({ name }): Option => ({ text: name, value: name })), - sub, - type - }; - } + subTypes + }); + setCurrent([{ name: subTypes[0].name, type: subTypes[0] }]); + }, [type]); - public render (): React.ReactNode { - const { className, defaultValue, isDisabled, isError, label, style, withLabel } = this.props; - - if (isDisabled) { - return ; - } - - const { def, options } = this.state; - const initialValue = defaultValue && defaultValue.value - ? defaultValue.value instanceof Enum - ? defaultValue.value.type - : Object.keys(defaultValue.value)[0] - : defaultValue; - - return ( - - - {def && ( - - )} - + useEffect((): void => { + setInitialValue( + defaultValue && defaultValue.value + ? defaultValue.value instanceof Enum + ? defaultValue.value.type + : Object.keys(defaultValue.value)[0] + : null ); + }, [defaultValue]); + + if (isDisabled) { + return ; } - private onChange = (value: string): void => { - this.setState(({ sub }): Pick => ({ - def: sub.find(({ name }): boolean => name === value) || null - })); - } + const _onChange = (value: string): void => { + const newType = subTypes.find(({ name }): boolean => name === value) || null; - private onChangeParam = ([{ isValid, value }]: RawParam[]): void => { - const { onChange } = this.props; - const { def } = this.state; + setCurrent( + newType + ? [{ name: newType.name, type: newType }] + : null + ); + }; - if (def) { - onChange && onChange({ - isValid, - value: { - [def.name as string]: value - } - }); - } - } + const _onChangeParam = ([{ isValid, value }]: RawParam[]): void => { + current && onChange && onChange({ + isValid, + value: { [current[0].name as string]: value } + }); + }; + + return ( + + + {current && ( + + )} + + ); } diff --git a/packages/react-params/src/Param/Struct.tsx b/packages/react-params/src/Param/Struct.tsx index 3506af80e9..34f5b482c3 100644 --- a/packages/react-params/src/Param/Struct.tsx +++ b/packages/react-params/src/Param/Struct.tsx @@ -3,86 +3,53 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { TypeDef } from '@polkadot/types/types'; -import { Props, RawParam } from '../types'; +import { ParamDef, Props, RawParam } from '../types'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { createType, getTypeDef } from '@polkadot/types'; import Params from '../'; import Base from './Base'; import Static from './Static'; -interface State { - defs: TypeDef[]; - type: string | null; -} +export default function StructParam (props: Props): React.ReactElement { + const { className, isDisabled, label, onChange, style, type, withLabel } = props; + const [params, setParams] = useState([]); -export default class StructParam extends React.PureComponent { - public state: State = { - defs: [], - type: null - }; - - public static getDerivedStateFromProps ({ type: { type } }: Props, prevState: State): State | null { - if (prevState.type === type) { - return null; - } - - const rawType = createType(type as any).toRawType(); + useEffect((): void => { + const rawType = createType(type.type as any).toRawType(); const typeDef = getTypeDef(rawType); - // HACK This is a quick hack to allow `Option` ... this is certainly not the right - // place for this, so we need to move it (even the detection just sucks)... also see enum - const defs = typeDef.type.startsWith('Option<') - ? (typeDef.sub as TypeDef).sub as TypeDef[] - : typeDef.sub as TypeDef[]; + setParams((typeDef.sub as TypeDef[]).map((type): ParamDef => ({ name: type.name, type }))); + }, [type]); - return { - defs, - type - } as unknown as State; + if (isDisabled) { + return ; } - public render (): React.ReactNode { - const { className, isDisabled, label, style, withLabel } = this.props; + const _onChangeParams = (values: RawParam[]): void => { + onChange && onChange({ + isValid: values.reduce((result, { isValid }): boolean => result && isValid, true as boolean), + value: params.reduce((value: Record, { name }, index): Record => { + value[name as string] = values[index].value; - if (isDisabled) { - return ; - } + return value; + }, {}) + }); + }; - const { defs } = this.state; - const params = defs.map((type): { name?: string; type: TypeDef } => ({ name: type.name, type })); - - return ( -
- - -
- ); - } - - private onChangeParams = (values: RawParam[]): void => { - const { onChange } = this.props; - - if (onChange) { - const { defs } = this.state; - - onChange({ - isValid: values.reduce((result, { isValid }): boolean => result && isValid, true as boolean), - value: defs.reduce((value, { name }, index): Record => { - value[name as string] = values[index].value; - - return value; - }, {} as unknown as Record) - }); - } - } + return ( +
+ + +
+ ); } diff --git a/packages/react-params/src/Param/Tuple.tsx b/packages/react-params/src/Param/Tuple.tsx index e72029cdcc..fe752f27f3 100644 --- a/packages/react-params/src/Param/Tuple.tsx +++ b/packages/react-params/src/Param/Tuple.tsx @@ -5,99 +5,69 @@ import { Codec, TypeDef } from '@polkadot/types/types'; import { Props, RawParam } from '../types'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { isUndefined } from '@polkadot/util'; import Bare from './Bare'; import findComponent from './findComponent'; -interface State { - Components: React.ComponentType[]; - sub: string[]; - subTypes: TypeDef[]; - type?: string; - values: RawParam[]; -} +export default function Tuple ({ className, defaultValue, isDisabled, onChange, onEnter, style, type, withLabel }: Props): React.ReactElement { + const [{ Components, subTypes }, setComponents] = useState<{ Components: React.ComponentType[]; subTypes: TypeDef[] }>({ Components: [], subTypes: [] }); + const [values, setValues] = useState([]); -export default class Tuple extends React.PureComponent { - public state: State = { - Components: [], - sub: [], - subTypes: [], - values: [] - }; - - public static getDerivedStateFromProps ({ defaultValue: { value }, type: { sub, type } }: Props, prevState: State): Partial | null { - if (type === prevState.type) { - return null; - } - - const subTypes = sub && Array.isArray(sub) - ? sub + useEffect((): void => { + const subTypes: TypeDef[] = type.sub && Array.isArray(type.sub) + ? type.sub : []; - const values = (value as any[]).map((value): { isValid: boolean; value: Codec } => - isUndefined(value) || isUndefined(value.isValid) - ? { - isValid: !isUndefined(value), - value - } - : value - ); - return { + setComponents({ Components: subTypes.map((type): React.ComponentType => findComponent(type)), - sub: subTypes.map(({ type }): string => type), - subTypes, - type, - values - }; - } + subTypes + }); + }, [type]); - public render (): React.ReactNode { - const { className, isDisabled, onEnter, style, withLabel } = this.props; - const { Components, sub, subTypes, values } = this.state; - - return ( - - {Components.map((Component, index): React.ReactNode => ( - - ))} - + useEffect((): void => { + setValues( + (((defaultValue && defaultValue.value) || []) as any[]).map((value): { isValid: boolean; value: Codec } => + isUndefined(value) || isUndefined(value.isValid) + ? { isValid: !isUndefined(value), value } + : value + ) ); - } + }, [defaultValue]); - private onChange = (index: number): (value: RawParam) => void => { - return (value: RawParam): void => { - this.setState( - ({ values }: State): State => ({ - values: values.map((svalue, sindex): RawParam => - (sindex === index) - ? value - : svalue - ) - } as unknown as State), - (): void => { - const { values } = this.state; - const { onChange } = this.props; + useEffect((): void => { + onChange && onChange({ + isValid: values.reduce((result: boolean, { isValid }): boolean => result && isValid, true), + value: values.map(({ value }): any => value) + }); + }, [values]); - onChange && onChange({ - isValid: values.reduce((result: boolean, { isValid }): boolean => result && isValid, true), - value: values.map(({ value }): any => value) - }); - } - ); - }; - } + const _onChange = (index: number): (value: RawParam) => void => + (value: RawParam): void => + setValues(values.map((prev, prevIndex): RawParam => + (prevIndex === index) + ? value + : prev + )); + + return ( + + {Components.map((Component, index): React.ReactNode => ( + + ))} + + ); }