You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

159 lines
4.7 KiB

/** @jsx jsx */
import { useRef } from 'react';
import { jsx } from '@emotion/core';
import { Row, Col, Tooltip, Input, Checkbox, Select } from 'antd';
import { useTranslation } from 'react-i18next';
import { useUIState, useSetUIState } from '../store/ui';
import { useSchemaDispatch } from '../store/schema';
import { schemaType } from '../utils/schema';
import { SchemaType, SchemaItem, KeyRoute } from '../model';
import FieldInput from './field-input';
import AddNode from './add-node';
import {
CaretDownIcon,
CaretRightIcon,
EditIcon,
SettingIcon,
PlusIcon,
CloseIcon,
} from '../utils/styles/common';
const { Option } = Select;
interface SchemaItemProps {
field: string;
data: SchemaItem;
required: boolean;
keyRoute: KeyRoute;
children: React.ReactChild | null;
}
function SchemaFormItem({
field,
data,
required,
keyRoute,
children,
}: SchemaItemProps): JSX.Element {
const fieldRef = useRef<Input>(null);
const { t } = useTranslation();
const schemaDispatch = useSchemaDispatch();
const setUIState = useSetUIState();
const uiState = useUIState();
const key = keyRoute.join('-');
const visible = uiState[key] !== false;
const toggleFormVisible = (): void => {
setUIState((prev) => ({ ...prev, [key]: !visible }));
};
const toggleRequired = (): void => {
if (!fieldRef.current) return;
const newField = fieldRef.current.state.value;
const fieldKeyRoute = keyRoute.slice(0, -1).concat(newField);
if (required) {
schemaDispatch({ type: 'REMOVE_REQUIRED', keyRoute: fieldKeyRoute });
} else {
schemaDispatch({ type: 'ADD_REQUIRED', keyRoute: fieldKeyRoute });
}
};
const addChildField = (): void => {
schemaDispatch({ type: 'ADD_CHILD_FIELD', keyRoute: keyRoute.concat('properties') });
};
const addSiblingField = (): void => {
schemaDispatch({ type: 'ADD_SIBLING_FIELD', keyRoute });
};
const removeField = (): void => {
schemaDispatch({ type: 'REMOVE_FIELD', keyRoute });
};
const changeField = (value: string): void => {
schemaDispatch({ type: 'CHANGE_FIELD', keyRoute, field: value });
};
const changeType = (value: SchemaType): void => {
schemaDispatch({ type: 'CHANGE_TYPE', keyRoute, fieldType: value });
};
const changeTitle = (e: React.ChangeEvent<HTMLInputElement>): void => {
schemaDispatch({ type: 'CHANGE_TITLE', keyRoute, title: e.target.value });
};
const changeDesc = (e: React.ChangeEvent<HTMLInputElement>): void => {
schemaDispatch({ type: 'CHANGE_DESC', keyRoute, desc: e.target.value });
};
return (
<div css={{ marginTop: '10px' }}>
<Row align="middle">
<Col span="8" css={{ paddingLeft: `${keyRoute.length * 10}px` }}>
<Row align="middle">
<Col span="2">
{data.type === 'object' && visible && <CaretDownIcon onClick={toggleFormVisible} />}
{data.type === 'object' && !visible && <CaretRightIcon onClick={toggleFormVisible} />}
</Col>
<Col span="22">
<FieldInput
ref={fieldRef}
value={field}
changeField={changeField}
addonAfter={
<Tooltip placement="top" title={t('required')}>
<Checkbox checked={required} onChange={toggleRequired} />
</Tooltip>
}
/>
</Col>
</Row>
</Col>
<Col span="3">
<Select value={data.type} onChange={changeType}>
{schemaType.map((type) => (
<Option key={type} value={type}>
{type}
</Option>
))}
</Select>
</Col>
<Col span="5">
<Input
value={data.title}
onChange={changeTitle}
placeholder={t('title')}
addonAfter={<EditIcon />}
/>
</Col>
<Col span="5">
<Input
value={data.description}
onChange={changeDesc}
placeholder={t('description')}
addonAfter={<EditIcon />}
/>
</Col>
<Col span="3">
<Tooltip placement="top" title={t('setting')}>
<SettingIcon />
</Tooltip>
<CloseIcon onClick={removeField} />
{data.type === 'object' ? (
<AddNode addChildField={addChildField} addSiblingField={addSiblingField} />
) : (
<Tooltip placement="top" title={t('add_sibling_node')}>
<PlusIcon onClick={addSiblingField} />
</Tooltip>
)}
</Col>
</Row>
{visible && children ? <div css={{ marginTop: '10px' }}>{children}</div> : null}
</div>
);
}
export default SchemaFormItem;