Browse Source

fix: 解决 field 更改后无法连贯更改属性的问题

master
suanmei 5 years ago
committed by 拾邑
parent
commit
e9aff5cec2
  1. 33
      packages/json-schema-editor/src/components/field-input.tsx
  2. 4
      packages/json-schema-editor/src/components/layout.tsx
  3. 5
      packages/json-schema-editor/src/components/schema-form.tsx
  4. 4
      packages/json-schema-editor/src/components/schema-head.tsx
  5. 29
      packages/json-schema-editor/src/components/schema-item.tsx
  6. 23
      packages/json-schema-editor/src/reducer/schema.ts

33
packages/json-schema-editor/src/components/field-input.tsx

@ -1,11 +1,13 @@
import * as React from 'react';
import styled from '@emotion/styled';
import { Input } from 'antd';
import { Tooltip, Input, Checkbox } from 'antd';
import { useTranslation } from 'react-i18next';
interface FieldInputProps {
value: string;
required: boolean;
changeField: (value: string) => void;
addonAfter: JSX.Element;
toggleRequired: (value: string) => void;
}
const CustomInput = styled(Input)`
@ -15,9 +17,18 @@ const CustomInput = styled(Input)`
}
`;
function FieldInput(props: FieldInputProps, ref: React.Ref<Input>): JSX.Element {
const { value: initValue, changeField, addonAfter } = props;
function FieldInput(props: FieldInputProps): JSX.Element {
const { value: initValue, changeField, required, toggleRequired } = props;
const [value, setValue] = React.useState(initValue);
const [prevInitValue, setPrevInitValue] = React.useState(initValue);
const { t } = useTranslation();
// mock getDerivedStateFromProps
if (initValue !== prevInitValue) {
setValue(initValue);
setPrevInitValue(initValue);
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
setValue(e.target.value);
@ -38,14 +49,22 @@ function FieldInput(props: FieldInputProps, ref: React.Ref<Input>): JSX.Element
return (
<CustomInput
ref={ref}
value={value}
onChange={handleChange}
onBlur={handleBlur}
onKeyUp={handleKeyUp}
addonAfter={addonAfter}
addonAfter={
<Tooltip placement="top" title={t('required')}>
<Checkbox
checked={required}
onChange={(): void => {
toggleRequired(value);
}}
/>
</Tooltip>
}
/>
);
}
export default React.forwardRef(FieldInput);
export default React.memo(FieldInput);

4
packages/json-schema-editor/src/components/layout.tsx

@ -11,11 +11,11 @@ import { SchemaState } from '../model';
let temp: SchemaState | null = null;
interface AA {
interface LayoutProps {
onChange: (value: SchemaState) => void;
}
function Layout({ onChange }: AA): JSX.Element {
function Layout({ onChange }: LayoutProps): JSX.Element {
const { t } = useTranslation();
const uiState = useUIState();

5
packages/json-schema-editor/src/components/schema-form.tsx

@ -14,14 +14,15 @@ function SchemaForm({ data, keyRoute }: SchemaFormProps): JSX.Element {
return (
<div>
{Object.keys(properties).map((field) => {
{Object.keys(properties).map((field, index) => {
const itemData = properties[field];
const isRequired = required && required.includes(field);
const fieldKeyRoute = keyRoute.concat(field);
return (
<SchemaItem
key={field}
// eslint-disable-next-line react/no-array-index-key
key={index}
field={field}
data={itemData}
required={isRequired}

4
packages/json-schema-editor/src/components/schema-head.tsx

@ -79,10 +79,10 @@ function EditorHead(): JSX.Element {
</Select>
</Col>
<Col span="5">
<Input value="" placeholder="Title" addonAfter={<EditIcon />} />
<Input value="" placeholder={t('title')} addonAfter={<EditIcon />} />
</Col>
<Col span="5">
<Input value="" placeholder="Description" addonAfter={<EditIcon />} />
<Input value="" placeholder={t('description')} addonAfter={<EditIcon />} />
</Col>
<Col span="3">
<Tooltip placement="top" title={t('setting')}>

29
packages/json-schema-editor/src/components/schema-item.tsx

@ -1,7 +1,6 @@
/** @jsx jsx */
import { useRef } from 'react';
import { jsx } from '@emotion/core';
import { Row, Col, Tooltip, Input, Checkbox, Select } from 'antd';
import { Row, Col, Tooltip, Input, Select } from 'antd';
import { useTranslation } from 'react-i18next';
import { useUIState, useSetUIState } from '../store/ui';
import { useSchemaDispatch } from '../store/schema';
@ -28,15 +27,8 @@ interface SchemaItemProps {
children: React.ReactChild | null;
}
function SchemaFormItem({
field,
data,
required,
keyRoute,
children,
}: SchemaItemProps): JSX.Element {
const fieldRef = useRef<Input>(null);
function SchemaFormItem(props: SchemaItemProps): JSX.Element {
const { field, data, required, keyRoute, children } = props;
const { t } = useTranslation();
const schemaDispatch = useSchemaDispatch();
const setUIState = useSetUIState();
@ -48,11 +40,8 @@ function SchemaFormItem({
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);
const toggleRequired = (value: string): void => {
const fieldKeyRoute = keyRoute.slice(0, -1).concat(value);
if (required) {
schemaDispatch({ type: 'REMOVE_REQUIRED', keyRoute: fieldKeyRoute });
@ -100,14 +89,10 @@ function SchemaFormItem({
</Col>
<Col span="22">
<FieldInput
ref={fieldRef}
value={field}
required={required}
changeField={changeField}
addonAfter={
<Tooltip placement="top" title={t('required')}>
<Checkbox checked={required} onChange={toggleRequired} />
</Tooltip>
}
toggleRequired={toggleRequired}
/>
</Col>
</Row>

23
packages/json-schema-editor/src/reducer/schema.ts

@ -1,5 +1,5 @@
import produce, { Draft } from 'immer';
import { get, set, unset, remove, cloneDeep } from 'lodash-es';
import { get, set, unset, remove } from 'lodash-es';
import { SchemaType, SchemaItem, SchemaState, SchemaAction, KeyRoute } from '../model';
import { defaultSchema, setAllFieldRequired } from '../utils/schema';
@ -25,6 +25,19 @@ const removeRequired = (state: SchemaState, keyRoute: KeyRoute): void => {
set(state, requiredKeyRoute, required);
};
const changeRequiredField = (state: SchemaState, oldKeyRoute: KeyRoute, newField: string): void => {
const oldField = oldKeyRoute.slice(-1)[0];
const requiredKeyRoute = oldKeyRoute.slice(0, -2).concat('required');
const required = get(state, requiredKeyRoute) || [];
const oldFieldIndex = required.indexOf(oldField);
// new field extend the old field
if (oldFieldIndex > -1) {
required.splice(oldFieldIndex, 1, newField);
set(state, requiredKeyRoute, required);
}
};
const toggleAllChecked = (state: SchemaState, checked: boolean): void => {
setAllFieldRequired(state, checked);
};
@ -82,12 +95,8 @@ const changeField = (state: SchemaState, keyRoute: KeyRoute, newField: string):
set(state, parentKeyRoute, newProperties);
// remove old filed from its parent's required
removeRequired(state, keyRoute);
// add new filed to its parent's required
const fieldKeyRoute = parentKeyRoute.concat(newField);
addRequired(state, fieldKeyRoute);
// replace old field with new field in required
changeRequiredField(state, keyRoute, newField);
};
const changeType = (state: SchemaState, keyRoute: KeyRoute, fieldType: SchemaType): void => {

Loading…
Cancel
Save