Components: add basic input elements

This commit is contained in:
Chika 2022-05-16 19:44:42 +03:00
parent d7f78af557
commit 5a23baa86c
18 changed files with 332 additions and 14 deletions

View File

@ -0,0 +1,30 @@
import { observer } from 'mobx-react-lite';
import { useOptions } from 'stores/calculation/options/hooks';
import { useStatus } from 'stores/calculation/statuses/hooks';
import { useValidation } from 'stores/calculation/validation/hooks';
import { useValue } from 'stores/calculation/values/hooks';
import { getValueName } from '../config/map';
import type { BuilderProps } from './types';
export default function buildValueElement({ elementName, Component, ...props }: BuilderProps) {
const valueName = getValueName(elementName);
return observer(() => {
const { value, setValue } = useValue(valueName);
const { status } = useStatus(elementName);
const { isValid, help } = useValidation(elementName);
const { options } = useOptions(elementName);
return (
<Component
value={value}
setValue={setValue}
options={options}
status={status}
isValid={isValid}
help={help}
{...props}
/>
);
});
}

View File

@ -0,0 +1,14 @@
import { observer } from 'mobx-react-lite';
import { useValue } from 'stores/calculation/values/hooks';
import { getValueName } from '../config/map';
import type { BuilderProps } from './types';
export default function buildValueElement({ elementName, Component, ...props }: BuilderProps) {
const valueName = getValueName(elementName);
return observer(() => {
const { value } = useValue(valueName);
return <Component value={value} {...props} />;
});
}

View File

@ -0,0 +1,27 @@
import { observer } from 'mobx-react-lite';
import { useStatus } from 'stores/calculation/statuses/hooks';
import { useValidation } from 'stores/calculation/validation/hooks';
import { useValue } from 'stores/calculation/values/hooks';
import { getValueName } from '../config/map';
import type { BuilderProps } from './types';
export default function buildValueElement({ elementName, Component, ...props }: BuilderProps) {
const valueName = getValueName(elementName);
return observer(() => {
const { value, setValue } = useValue(valueName);
const { status } = useStatus(elementName);
const { isValid, help } = useValidation(elementName);
return (
<Component
value={value}
setValue={setValue}
status={status}
isValid={isValid}
help={help}
{...props}
/>
);
});
}

View File

@ -0,0 +1,8 @@
import type { FC } from 'react';
import type { Elements } from '../config/map';
export interface BuilderProps {
elementName: Elements;
Component: FC<any>;
style: React.CSSProperties;
}

27
Elements/Checkbox.tsx Normal file
View File

@ -0,0 +1,27 @@
import type { CheckboxProps } from 'antd';
import { Checkbox, Form } from 'antd';
import type { BaseElementProps } from './types';
const { Item: FormItem } = Form;
export default function Element({
value,
setValue,
status,
isValid,
help,
...props
}: BaseElementProps<boolean>) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<Checkbox
checked={value}
onChange={(e) => setValue(e.target.value)}
disabled={status === 'Disabled'}
{...props}
/>
</FormItem>
);
}
export type { CheckboxProps };

27
Elements/Input.tsx Normal file
View File

@ -0,0 +1,27 @@
import type { InputProps } from 'antd';
import { Form, Input } from 'antd';
import type { BaseElementProps } from './types';
const { Item: FormItem } = Form;
export default function Element({
value,
setValue,
status,
isValid,
help,
...props
}: BaseElementProps<string>) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<Input
defaultValue={value}
onChange={(e) => setValue(e.target.value)}
disabled={status === 'Disabled'}
{...props}
/>
</FormItem>
);
}
export type { InputProps };

34
Elements/InputNumber.tsx Normal file
View File

@ -0,0 +1,34 @@
import type { InputNumberProps } from 'antd';
import { Form, InputNumber } from 'antd';
import type { BaseElementProps } from './types';
const { Item: FormItem } = Form;
const parser = (val?: string): number => {
const res = val?.replace(/[^0-9.,]+/, '');
if (!res || res === '') return 0;
return parseFloat(res);
};
export default function Element({
value = 0,
setValue,
status,
isValid,
help,
...props
}: BaseElementProps<number>) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<InputNumber
defaultValue={value}
onChange={(val) => setValue(val)}
disabled={status === 'Disabled'}
parser={parser}
{...props}
/>
</FormItem>
);
}
export type { InputNumberProps };

20
Elements/Link.tsx Normal file
View File

@ -0,0 +1,20 @@
import DownloadOutlined from '@ant-design/icons/lib/icons/DownloadOutlined';
import type { ButtonProps } from 'antd';
import { Button } from 'antd';
import type { BaseElementProps } from './types';
export default function Element({ value, setValue, status, ...props }: BaseElementProps<string>) {
return (
<Button
rel="noopener"
target="_blank"
href={value}
disabled={status === 'Disabled'}
loading={status === 'Loading'}
icon={<DownloadOutlined />}
{...props}
/>
);
}
export type { ButtonProps as LinkProps };

33
Elements/Radio.tsx Normal file
View File

@ -0,0 +1,33 @@
import type { RadioProps } from 'antd';
import { Form, Radio } from 'antd';
import type { BaseElementProps, BaseOption } from './types';
const { Item: FormItem } = Form;
type ElementProps = BaseElementProps<string | null> & {
options: BaseOption[];
};
export default function Element({
value = null,
setValue,
options,
status,
isValid,
help,
...props
}: ElementProps) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<Radio.Group
defaultValue={value}
options={options}
onChange={(e) => setValue(e.target.value)}
disabled={status === 'Disabled'}
{...props}
/>
</FormItem>
);
}
export type { RadioProps };

40
Elements/Select.tsx Normal file
View File

@ -0,0 +1,40 @@
import type { SelectProps } from 'antd';
import { Form, Select } from 'antd';
import type { BaseElementProps, BaseOption } from './types';
const { Item: FormItem } = Form;
type ElementProps = BaseElementProps<string | null> & {
options: BaseOption[];
};
export default function Element({
value = null,
setValue,
options,
status,
isValid,
help,
...props
}: ElementProps) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<Select
defaultValue={value}
onChange={(val) => setValue(val)}
disabled={status === 'Disabled'}
loading={status === 'Loading'}
optionFilterProp="children"
options={[
{
label: 'Не выбрано',
value: null,
},
].concat(options)}
{...props}
/>
</FormItem>
);
}
export type { SelectProps };

27
Elements/Switch.tsx Normal file
View File

@ -0,0 +1,27 @@
import type { SwitchProps } from 'antd';
import { Form, Switch } from 'antd';
import type { BaseElementProps } from './types';
const { Item: FormItem } = Form;
export default function Element({
value,
setValue,
status,
isValid,
help,
...props
}: BaseElementProps<boolean>) {
return (
<FormItem hasFeedback validateStatus={isValid === false ? 'error' : ''} help={help}>
<Switch
checked={value}
onChange={(enabled) => setValue(enabled)}
disabled={status === 'Disabled'}
{...props}
/>
</FormItem>
);
}
export type { SwitchProps };

17
Elements/Text.tsx Normal file
View File

@ -0,0 +1,17 @@
import styled from 'styled-components';
import type { BaseElementProps } from './types';
const Text = styled.span`
margin-bottom: 18px;
font-size: 0.85rem;
`;
export default function Element({ value, ...props }: BaseElementProps<string>) {
return <Text {...props}>{value}</Text>;
}
type TextProps = {
middleware: (value: any) => string;
};
export type { TextProps };

15
Elements/types.ts Normal file
View File

@ -0,0 +1,15 @@
export type Status = 'Default' | 'Disabled' | 'Loading' | 'Hidden';
export type BaseElementProps<ValueType> = {
value: ValueType;
setValue: (value: ValueType) => void;
status: Status;
isValid: boolean;
help: string;
};
export type BaseOption = {
name: string;
label: string;
value: any;
};

View File

@ -4,10 +4,11 @@
/* eslint-disable object-curly-newline */
/* eslint-disable import/no-cycle */
import type { Elements } from 'Components/Calculation/config/map';
import type { BaseOption } from 'Elements/types';
import { mergeWith } from 'lodash';
import { makeAutoObservable } from 'mobx';
import RootStore from 'stores/root';
import { CalculationOptions, Filter, Options, OptionsFilters } from './types';
import type { CalculationOptions, Filter, OptionsFilters } from './types';
const EXCLUDE_RESET_ELEMENTS: Elements[] = ['selectTechnicalCard', 'selectTownRegistration'];
@ -59,7 +60,7 @@ export default class OptionsStore {
return filter ? options && filter(options) : options;
}
setOptions = (elementName: Elements, options: Options) => {
setOptions = (elementName: Elements, options: BaseOption[]) => {
this.options[elementName] = options;
};

View File

@ -1,12 +1,7 @@
import type { Elements } from 'Components/Calculation/config/map';
import type { BaseOption } from 'Elements/types';
export type BaseOption = {
name: string;
value: any;
};
export type CalculationOptions = Record<Elements, BaseOption[]>;
export type Options = BaseOption[];
export type CalculationOptions = Record<Elements, Options>;
export type Filter = (options: Options) => Options;
export type Filter = (options: BaseOption[]) => BaseOption[];
export type OptionsFilters = Record<Elements, Filter>;

View File

@ -1,9 +1,10 @@
/* eslint-disable object-curly-newline */
/* eslint-disable import/no-cycle */
import type { Elements } from 'Components/Calculation/config/map';
import type { Status } from 'Elements/types';
import { makeAutoObservable } from 'mobx';
import RootStore from 'stores/root';
import type { CalculationStatuses, Status } from './types';
import type { CalculationStatuses } from './types';
export default class StatusStore {
root: RootStore;

View File

@ -1,5 +1,4 @@
import type { Elements } from 'Components/Calculation/config/map';
export type Status = 'Default' | 'Disabled' | 'Loading' | 'Hidden';
import type { Status } from 'Elements/types';
export type CalculationStatuses = Partial<Record<Elements, Status>>;

View File

@ -11,5 +11,8 @@ export function useValidation(elementName) {
[$calculation.$validation, elementName]
);
return validationResult.get();
return {
...validationResult.get(),
help: 'Некорректные данные',
};
}