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 * as React from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Input } from 'antd'; import { Tooltip, Input, Checkbox } from 'antd';
import { useTranslation } from 'react-i18next';
interface FieldInputProps { interface FieldInputProps {
value: string; value: string;
required: boolean;
changeField: (value: string) => void; changeField: (value: string) => void;
addonAfter: JSX.Element; toggleRequired: (value: string) => void;
} }
const CustomInput = styled(Input)` const CustomInput = styled(Input)`
@ -15,9 +17,18 @@ const CustomInput = styled(Input)`
} }
`; `;
function FieldInput(props: FieldInputProps, ref: React.Ref<Input>): JSX.Element { function FieldInput(props: FieldInputProps): JSX.Element {
const { value: initValue, changeField, addonAfter } = props; const { value: initValue, changeField, required, toggleRequired } = props;
const [value, setValue] = React.useState(initValue); 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 => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
setValue(e.target.value); setValue(e.target.value);
@ -38,14 +49,22 @@ function FieldInput(props: FieldInputProps, ref: React.Ref<Input>): JSX.Element
return ( return (
<CustomInput <CustomInput
ref={ref}
value={value} value={value}
onChange={handleChange} onChange={handleChange}
onBlur={handleBlur} onBlur={handleBlur}
onKeyUp={handleKeyUp} 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; let temp: SchemaState | null = null;
interface AA { interface LayoutProps {
onChange: (value: SchemaState) => void; onChange: (value: SchemaState) => void;
} }
function Layout({ onChange }: AA): JSX.Element { function Layout({ onChange }: LayoutProps): JSX.Element {
const { t } = useTranslation(); const { t } = useTranslation();
const uiState = useUIState(); 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 ( return (
<div> <div>
{Object.keys(properties).map((field) => { {Object.keys(properties).map((field, index) => {
const itemData = properties[field]; const itemData = properties[field];
const isRequired = required && required.includes(field); const isRequired = required && required.includes(field);
const fieldKeyRoute = keyRoute.concat(field); const fieldKeyRoute = keyRoute.concat(field);
return ( return (
<SchemaItem <SchemaItem
key={field} // eslint-disable-next-line react/no-array-index-key
key={index}
field={field} field={field}
data={itemData} data={itemData}
required={isRequired} required={isRequired}

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

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

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

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

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

@ -1,5 +1,5 @@
import produce, { Draft } from 'immer'; 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 { SchemaType, SchemaItem, SchemaState, SchemaAction, KeyRoute } from '../model';
import { defaultSchema, setAllFieldRequired } from '../utils/schema'; import { defaultSchema, setAllFieldRequired } from '../utils/schema';
@ -25,6 +25,19 @@ const removeRequired = (state: SchemaState, keyRoute: KeyRoute): void => {
set(state, requiredKeyRoute, required); 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 => { const toggleAllChecked = (state: SchemaState, checked: boolean): void => {
setAllFieldRequired(state, checked); setAllFieldRequired(state, checked);
}; };
@ -82,12 +95,8 @@ const changeField = (state: SchemaState, keyRoute: KeyRoute, newField: string):
set(state, parentKeyRoute, newProperties); set(state, parentKeyRoute, newProperties);
// remove old filed from its parent's required // replace old field with new field in required
removeRequired(state, keyRoute); changeRequiredField(state, keyRoute, newField);
// add new filed to its parent's required
const fieldKeyRoute = parentKeyRoute.concat(newField);
addRequired(state, fieldKeyRoute);
}; };
const changeType = (state: SchemaState, keyRoute: KeyRoute, fieldType: SchemaType): void => { const changeType = (state: SchemaState, keyRoute: KeyRoute, fieldType: SchemaType): void => {

Loading…
Cancel
Save