From 8f7c4c6a624941e10c624dc3098e4e601639d25e Mon Sep 17 00:00:00 2001 From: Nikita Zolotykh <58661343+bocembocem@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:54:26 +0200 Subject: [PATCH] feat: add store and entity unmount callbacks (#55) --- src/lib/core/components/Form/constants.ts | 2 - .../Form/hooks/__tests__/useField.test.tsx | 45 ++++++++------ .../core/components/Form/hooks/useField.tsx | 62 +++++++++---------- .../Form/hooks/useIntegrationFF.tsx | 12 +++- src/lib/core/components/Form/types/field.ts | 1 + src/lib/core/components/Form/utils/common.ts | 9 +-- .../components/Inputs/ArrayBase/ArrayBase.tsx | 17 +---- .../components/Inputs/CardOneOf/CardOneOf.tsx | 7 +-- .../Inputs/ObjectBase/ObjectBase.tsx | 9 +-- .../ObjectValueInput/ObjectValueInput.tsx | 7 +-- src/lib/kit/components/Inputs/OneOf/OneOf.tsx | 8 +-- .../components/Inputs/OneOfCard/OneOfCard.tsx | 7 +-- .../kit/components/Inputs/Secret/Secret.tsx | 7 +-- .../TableArrayInput/TableArrayInput.tsx | 17 +---- .../components/Inputs/TextLink/TextLink.tsx | 7 +-- src/stories/Editor.stories.tsx | 33 +++++----- .../components/DynamicField/DynamicField.tsx | 10 ++- src/stories/components/Editor/Editor.tsx | 31 ++++++++-- .../components/InputPreview/SpecSelector.tsx | 8 +-- 19 files changed, 137 insertions(+), 162 deletions(-) diff --git a/src/lib/core/components/Form/constants.ts b/src/lib/core/components/Form/constants.ts index 2c8ceb15..7a6a06ad 100644 --- a/src/lib/core/components/Form/constants.ts +++ b/src/lib/core/components/Form/constants.ts @@ -1,5 +1,3 @@ -export const REMOVED_ITEM = '____removed-item'; - export const OBJECT_ARRAY_FLAG = '____arr-obj'; export const OBJECT_ARRAY_CNT = '____arr-obj-cnt'; diff --git a/src/lib/core/components/Form/hooks/__tests__/useField.test.tsx b/src/lib/core/components/Form/hooks/__tests__/useField.test.tsx index 27b49c2d..84cf527d 100644 --- a/src/lib/core/components/Form/hooks/__tests__/useField.test.tsx +++ b/src/lib/core/components/Form/hooks/__tests__/useField.test.tsx @@ -8,7 +8,7 @@ import {ErrorMessages, dynamicConfig} from '../../../../../kit'; import {SpecTypes} from '../../../../constants'; import {ArraySpec, ObjectSpec, StringSpec} from '../../../../types'; import {DynamicField} from '../../DynamicField'; -import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM} from '../../constants'; +import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG} from '../../constants'; import {WonderMirror} from '../../types'; const spec: ObjectSpec = {type: SpecTypes.Object, viewSpec: {type: ''}}; @@ -356,15 +356,25 @@ describe('Form/hooks/useField', () => { test('onDrop (array item)', () => { const mirror: WonderMirror = {field: {}, controller: {}}; - const _name = `${name}>`; - const _value = {[_name]: value[name]}; + const _spec: ArraySpec = { + type: SpecTypes.Array, + items: {type: SpecTypes.String, viewSpec: {type: ''}}, + viewSpec: {type: 'base'}, + }; + const _value = { + [name]: { + '<0>': 'item', + [OBJECT_ARRAY_FLAG]: true, + [OBJECT_ARRAY_CNT]: 1, + }, + }; render(
{() => ( @@ -373,21 +383,19 @@ describe('Form/hooks/useField', () => { ); act(() => { - mirror.controller[_name]?.useField?.input.onDrop(); + mirror.controller[`${name}.<0>`]?.useField?.input.onDrop(); }); - expect(mirror.controller[_name]?.useField?.input.value).toBe(REMOVED_ITEM); - expect(mirror.controller[_name]?.useField?.arrayInput.value).toBe(REMOVED_ITEM); - expect(mirror.field.useStore?.store.values[_name]).toBe(REMOVED_ITEM); - expect(mirror.field.useStore?.store.errors[_name]).toBe(undefined); - - expect(mirror.controller[_name]?.useField?.meta.dirty).toBe(true); - expect(mirror.controller[_name]?.useField?.meta.error).toBe(undefined); - expect(mirror.controller[_name]?.useField?.meta.invalid).toBe(false); - expect(mirror.controller[_name]?.useField?.meta.modified).toBe(true); - expect(mirror.controller[_name]?.useField?.meta.touched).toBe(true); - expect(mirror.controller[_name]?.useField?.meta.valid).toBe(true); - expect(mirror.controller[_name]?.useField?.meta.visited).toBe(true); + const nextValue = { + [OBJECT_ARRAY_FLAG]: true, + [OBJECT_ARRAY_CNT]: 1, + }; + + expect(mirror.controller[name]?.useField?.input.value).toMatchObject(nextValue); + expect(mirror.controller[name]?.useField?.arrayInput.value).toMatchObject(nextValue); + expect(mirror.field.useStore?.store.values[name]).toMatchObject(nextValue); + + expect(mirror.controller[`${name}.<0>`]).toBe(undefined); }); test('onItemAdd/onItemRemove', () => { @@ -576,7 +584,6 @@ describe('Form/hooks/useField', () => { }); const nextValue1 = { - '<0>': REMOVED_ITEM, '____arr-obj': true, '____arr-obj-cnt': 1, }; diff --git a/src/lib/core/components/Form/hooks/useField.tsx b/src/lib/core/components/Form/hooks/useField.tsx index 0984a1e5..15b129a9 100644 --- a/src/lib/core/components/Form/hooks/useField.tsx +++ b/src/lib/core/components/Form/hooks/useField.tsx @@ -4,10 +4,11 @@ import _ from 'lodash'; import {isArraySpec, isNumberSpec, isObjectSpec} from '../../../helpers'; import {Spec} from '../../../types'; -import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM} from '../constants'; +import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG} from '../constants'; import { DynamicFormsContext, FieldArrayValue, + FieldObjectValue, FieldRenderProps, FieldValue, ValidateError, @@ -39,18 +40,12 @@ export const useField = ({ validate: propsValidate, tools, parentOnChange, - parentOnUnmount, + parentOnUnmount: externalParentOnUnmount, }: UseFieldProps): FieldRenderProps => { const firstRenderRef = React.useRef(true); const validate = React.useCallback( - (value: Value) => { - if (value === REMOVED_ITEM) { - return; - } - - return propsValidate?.(transformArrOut(value)); - }, + (value: Value) => propsValidate?.(transformArrOut(value)), [propsValidate], ); @@ -101,7 +96,7 @@ export const useField = ({ const error = validate?.(_value); let value = transformArrIn(_value); - if (isNumberSpec(spec) && value && value !== REMOVED_ITEM && !error) { + if (isNumberSpec(spec) && value && !error) { value = Number(value) as Value; } @@ -142,14 +137,14 @@ export const useField = ({ const onDrop = () => { if (isArrayItem(name)) { - onChange(REMOVED_ITEM as Value); + (externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name); } else { onChange(undefined as Value); } }; return {onChange, onDrop}; - }, [initialValue, setState, name, validate, spec]); + }, [initialValue, setState, name, validate, spec, externalParentOnUnmount, tools.onUnmount]); const onBlur = React.useCallback(() => { setState((state) => ({ @@ -167,6 +162,26 @@ export const useField = ({ })); }, [setState]); + const parentOnUnmount = React.useCallback( + (childName: string) => { + if (isArraySpec(spec) || isObjectSpec(spec)) { + onChange( + (currentValue) => + currentValue + ? (_.omit( + currentValue as FieldArrayValue | FieldObjectValue, + childName.split(`${name}.`)[1], + ) as Value) + : currentValue, + { + [childName]: false, + }, + ); + } + }, + [onChange, name, spec], + ); + const renderProps: FieldRenderProps = React.useMemo(() => { const onItemAdd = (_value: FieldValue) => { const stateValue = (state.value || { @@ -195,24 +210,7 @@ export const useField = ({ }; const onItemRemove = (idx: string | number) => { - const value = { - ...(state.value as FieldArrayValue), - [`<${idx}>`]: REMOVED_ITEM, - } as Value; - const error = validate?.(value); - - setState((state) => ({ - ...state, - dirty: !_.isEqual(value, initialValue), - error, - invalid: Boolean(error), - modified: true, - pristine: value === initialValue, - touched: true, - valid: !error, - value, - visited: true, - })); + parentOnUnmount(`${name}.<${idx}>`); }; return { @@ -223,6 +221,7 @@ export const useField = ({ onBlur, onFocus, onDrop, + parentOnUnmount, }, arrayInput: { name, @@ -244,6 +243,7 @@ export const useField = ({ onBlur, onFocus, onDrop, + parentOnUnmount, ]); React.useEffect(() => { @@ -259,7 +259,7 @@ export const useField = ({ firstRenderRef.current = false; return () => { - (parentOnUnmount ? parentOnUnmount : tools.onUnmount)(name); + (externalParentOnUnmount ? externalParentOnUnmount : tools.onUnmount)(name); }; }, []); diff --git a/src/lib/core/components/Form/hooks/useIntegrationFF.tsx b/src/lib/core/components/Form/hooks/useIntegrationFF.tsx index df095ab0..7aa15e19 100644 --- a/src/lib/core/components/Form/hooks/useIntegrationFF.tsx +++ b/src/lib/core/components/Form/hooks/useIntegrationFF.tsx @@ -42,7 +42,9 @@ export const useIntegrationFF = (store: DynamicFieldStore, withoutDebounce?: boo const change = React.useMemo(() => { const cb = (value: FieldValue) => { - form.change(store.name, _.get(transformArrOut(value), store.name)); + if (store.name) { + form.change(store.name, _.get(transformArrOut(value), store.name)); + } }; if (withoutDebounce) { @@ -56,5 +58,13 @@ export const useIntegrationFF = (store: DynamicFieldStore, withoutDebounce?: boo change(store.values); }, [store.values]); + React.useEffect(() => { + return () => { + if (store.name) { + form.change(store.name, undefined); + } + }; + }, []); + return watcher; }; diff --git a/src/lib/core/components/Form/types/field.ts b/src/lib/core/components/Form/types/field.ts index 61ddb015..7461c9ed 100644 --- a/src/lib/core/components/Form/types/field.ts +++ b/src/lib/core/components/Form/types/field.ts @@ -13,6 +13,7 @@ export interface FieldRenderProps { ) => void; onFocus: (event?: React.FocusEvent) => void; onDrop: () => void; + parentOnUnmount: (childName: string) => void; }; arrayInput: { name: string; diff --git a/src/lib/core/components/Form/utils/common.ts b/src/lib/core/components/Form/utils/common.ts index 613a073d..dfc940b2 100644 --- a/src/lib/core/components/Form/utils/common.ts +++ b/src/lib/core/components/Form/utils/common.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; import {SpecTypes} from '../../../constants'; import {FormValue, ObjectValue} from '../../../types'; -import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM} from '../constants'; +import {OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG} from '../constants'; export const isCorrectConfig = (candidate: any) => Object.values(SpecTypes).every( @@ -47,12 +47,7 @@ export const transformArrOut = - key !== OBJECT_ARRAY_FLAG && - key !== OBJECT_ARRAY_CNT && - (value as ObjectValue)[key] !== REMOVED_ITEM, - ) + .filter((key) => key !== OBJECT_ARRAY_FLAG && key !== OBJECT_ARRAY_CNT) .map((key) => key.split('<').join('').split('>').join('')) .sort((a, b) => Number(a) - Number(b)) .map((key) => transformArrOut((value as ObjectValue)[`<${key}>`])) as ReturnType; diff --git a/src/lib/kit/components/Inputs/ArrayBase/ArrayBase.tsx b/src/lib/kit/components/Inputs/ArrayBase/ArrayBase.tsx index de05d669..9439b4e9 100644 --- a/src/lib/kit/components/Inputs/ArrayBase/ArrayBase.tsx +++ b/src/lib/kit/components/Inputs/ArrayBase/ArrayBase.tsx @@ -12,7 +12,6 @@ import { FieldValue, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, - REMOVED_ITEM, Spec, ValidateError, isArraySpec, @@ -25,12 +24,7 @@ export const ArrayBase: ArrayInput = ({spec, name, arrayInput, input}) => { const keys = React.useMemo( () => Object.keys(arrayInput.value || {}) - .filter( - (k) => - k !== OBJECT_ARRAY_FLAG && - k !== OBJECT_ARRAY_CNT && - arrayInput.value[k] !== REMOVED_ITEM, - ) + .filter((k) => k !== OBJECT_ARRAY_FLAG && k !== OBJECT_ARRAY_CNT) .map((k) => k.split('<').join('').split('>').join('')) .sort((a, b) => Number(a) - Number(b)), [arrayInput.value], @@ -86,11 +80,6 @@ export const ArrayBase: ArrayInput = ({spec, name, arrayInput, input}) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - const items = React.useMemo( () => keys.map((key, idx) => { @@ -104,14 +93,14 @@ export const ArrayBase: ArrayInput = ({spec, name, arrayInput, input}) => { `]} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} spec={itemSpec} name={`${name}.<${key}>`} key={`${name}.<${key}>`} /> ); }), - [keys.join(''), name, getItemSpec, parentOnChange, parentOnUnmount, input.value], + [keys.join(''), name, getItemSpec, parentOnChange, input.parentOnUnmount, input.value], ); if (!itemSpecCorrect) { diff --git a/src/lib/kit/components/Inputs/CardOneOf/CardOneOf.tsx b/src/lib/kit/components/Inputs/CardOneOf/CardOneOf.tsx index 79ce75b8..e94b7009 100644 --- a/src/lib/kit/components/Inputs/CardOneOf/CardOneOf.tsx +++ b/src/lib/kit/components/Inputs/CardOneOf/CardOneOf.tsx @@ -57,11 +57,6 @@ export const CardOneOf: ObjectIndependentInput = (props) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - useErrorChecker({name, meta, open, setOpen}); return ( @@ -80,7 +75,7 @@ export const CardOneOf: ObjectIndependentInput = (props) => { spec={specProperties[oneOfValue]} name={`${name}.${oneOfValue}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} key={`${name}.${oneOfValue}`} /> ) : null} diff --git a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx index 0ed05550..3f0d6a83 100644 --- a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx +++ b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx @@ -48,11 +48,6 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP [restProps.input.onChange, restProps.input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => - restProps.input.onChange((currentValue) => currentValue, {[childName]: false}), - [restProps.input.onChange], - ); const content = React.useMemo(() => { if (!_.isObjectLike(spec.properties) || !Object.keys(spec.properties || {}).length) { return null; @@ -73,7 +68,7 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP spec={specProperties[property]} name={`${name ? name + '.' : ''}${property}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={restProps.input.parentOnUnmount} key={`${name ? name + '.' : ''}${property}`} /> ) : null, @@ -87,7 +82,7 @@ export const ObjectBase: ObjectIndependentInput = ({spec, name, Layout, ...restP restProps.input.value, addBtn, parentOnChange, - parentOnUnmount, + restProps.input.parentOnUnmount, ]); if (!Layout || !content) { diff --git a/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx b/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx index 68486a10..87c1d3ef 100644 --- a/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx +++ b/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx @@ -19,11 +19,6 @@ export const ObjectValueInput: ObjectIndependentInput = (props) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - const childSpec = React.useMemo(() => { if (spec.properties?.[OBJECT_VALUE_PROPERTY_NAME]) { const childSpec = _.cloneDeep(spec.properties[OBJECT_VALUE_PROPERTY_NAME]); @@ -47,7 +42,7 @@ export const ObjectValueInput: ObjectIndependentInput = (props) => { name={`${name}.${OBJECT_VALUE_PROPERTY_NAME}`} key={`${name}.${OBJECT_VALUE_PROPERTY_NAME}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} /> ); diff --git a/src/lib/kit/components/Inputs/OneOf/OneOf.tsx b/src/lib/kit/components/Inputs/OneOf/OneOf.tsx index ebe2d3c4..e9f3fb26 100644 --- a/src/lib/kit/components/Inputs/OneOf/OneOf.tsx +++ b/src/lib/kit/components/Inputs/OneOf/OneOf.tsx @@ -37,12 +37,6 @@ const OneOfComponent: React.FC = (props) => { [props.input.onChange, props.input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => - props.input.onChange((currentValue) => currentValue, {[childName]: false}), - [props.input.onChange], - ); - return (
= (props) => { spec={specProperties[oneOfValue]} name={`${props.name}.${oneOfValue}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={props.input.parentOnUnmount} key={`${props.name}.${oneOfValue}`} /> diff --git a/src/lib/kit/components/Inputs/OneOfCard/OneOfCard.tsx b/src/lib/kit/components/Inputs/OneOfCard/OneOfCard.tsx index c28521b1..0b7d6d72 100644 --- a/src/lib/kit/components/Inputs/OneOfCard/OneOfCard.tsx +++ b/src/lib/kit/components/Inputs/OneOfCard/OneOfCard.tsx @@ -74,11 +74,6 @@ export const OneOfCard: ObjectIndependentInput = (props) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - useErrorChecker({name, meta, open, setOpen}); return ( @@ -98,7 +93,7 @@ export const OneOfCard: ObjectIndependentInput = (props) => { spec={specProperties[oneOfValue]} name={`${name}.${oneOfValue}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} key={`${name}.${oneOfValue}`} /> ) : null} diff --git a/src/lib/kit/components/Inputs/Secret/Secret.tsx b/src/lib/kit/components/Inputs/Secret/Secret.tsx index 051d15c4..5b7c593e 100644 --- a/src/lib/kit/components/Inputs/Secret/Secret.tsx +++ b/src/lib/kit/components/Inputs/Secret/Secret.tsx @@ -35,11 +35,6 @@ export const Secret: ObjectIndependentInput = (props) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - if (!childSpec) { return null; } @@ -50,7 +45,7 @@ export const Secret: ObjectIndependentInput = (props) => { spec={childSpec} name={`${name}.${SECRET_PROPERTY_NAME}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} key={`${name}.${SECRET_PROPERTY_NAME}`} /> ); diff --git a/src/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.tsx b/src/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.tsx index 4ea508f2..c2d96459 100644 --- a/src/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.tsx +++ b/src/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.tsx @@ -13,7 +13,6 @@ import { FieldValue, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, - REMOVED_ITEM, ValidateError, isArraySpec, isBooleanSpec, @@ -33,12 +32,7 @@ export const TableArrayInput: ArrayInput = ({spec, name, arrayInput, input}) => const keys = React.useMemo( () => Object.keys(arrayInput.value || {}) - .filter( - (k) => - k !== OBJECT_ARRAY_FLAG && - k !== OBJECT_ARRAY_CNT && - arrayInput.value[k] !== REMOVED_ITEM, - ) + .filter((k) => k !== OBJECT_ARRAY_FLAG && k !== OBJECT_ARRAY_CNT) .map((k) => k.split('<').join('').split('>').join('')) .sort((a, b) => Number(a) - Number(b)) .map((key) => ({ @@ -72,11 +66,6 @@ export const TableArrayInput: ArrayInput = ({spec, name, arrayInput, input}) => [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - const columns = React.useMemo(() => { const { items, @@ -154,7 +143,7 @@ export const TableArrayInput: ArrayInput = ({spec, name, arrayInput, input}) => spec={preparedEntitySpec} name={`${name}.<${key}>.${property}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={_.noop} />
); @@ -162,7 +151,7 @@ export const TableArrayInput: ArrayInput = ({spec, name, arrayInput, input}) => })); return [idxColumn, ...columns, removeColumn]; - }, [name, spec, onItemRemove, parentOnChange, parentOnUnmount, input.value]); + }, [name, spec, onItemRemove, parentOnChange, input.parentOnUnmount, input.value]); const getRowClassNames = React.useCallback( ({key}: {key: string}) => { diff --git a/src/lib/kit/components/Inputs/TextLink/TextLink.tsx b/src/lib/kit/components/Inputs/TextLink/TextLink.tsx index ef9019ef..37580081 100644 --- a/src/lib/kit/components/Inputs/TextLink/TextLink.tsx +++ b/src/lib/kit/components/Inputs/TextLink/TextLink.tsx @@ -25,11 +25,6 @@ export const TextLink: ObjectIndependentInput = (props) => { [input.onChange, input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => input.onChange((currentValue) => currentValue, {[childName]: false}), - [input.onChange], - ); - const childSpec = React.useMemo(() => { if ( spec.properties?.[TEXT_LINK_PROPERTY_NAME] && @@ -56,7 +51,7 @@ export const TextLink: ObjectIndependentInput = (props) => { name={`${name}.${TEXT_LINK_PROPERTY_NAME}`} key={`${name}.${TEXT_LINK_PROPERTY_NAME}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={input.parentOnUnmount} /> ); diff --git a/src/stories/Editor.stories.tsx b/src/stories/Editor.stories.tsx index 45ddce0c..3455c1da 100644 --- a/src/stories/Editor.stories.tsx +++ b/src/stories/Editor.stories.tsx @@ -12,6 +12,21 @@ export default { }; const spec: ObjectSpec = { + defaultValue: { + id: 12345, + name: 'Foo', + description: + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla quod error voluptatibus odio minima assumenda voluptatum harum quidem maxime iste exercitationem, quam numquam, necessitatibus saepe praesentium, commodi beatae. Vitae, odit. Assumenda nobis similique voluptatibus? Sint itaque qui laudantium iste? In doloribus nam vitae quasi suscipit dolores maiores culpa amet quo. Distinctio mollitia ad expedita tempore sit? Nemo odit quae impedit?', + labels: ['foo', 'bar', 'rab', 'oof'], + settings: true, + autor: { + external: { + name: 'Bar', + age: 12345, + license: true, + }, + }, + }, required: true, type: SpecTypes.Object, properties: { @@ -105,25 +120,9 @@ const spec: ObjectSpec = { }, }; -const value = { - id: 12345, - name: 'Foo', - description: - 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla quod error voluptatibus odio minima assumenda voluptatum harum quidem maxime iste exercitationem, quam numquam, necessitatibus saepe praesentium, commodi beatae. Vitae, odit. Assumenda nobis similique voluptatibus? Sint itaque qui laudantium iste? In doloribus nam vitae quasi suscipit dolores maiores culpa amet quo. Distinctio mollitia ad expedita tempore sit? Nemo odit quae impedit?', - labels: ['foo', 'bar', 'rab', 'oof'], - settings: true, - autor: { - external: { - name: 'Bar', - age: 12345, - license: true, - }, - }, -}; - const template = () => { const Template: ComponentStory = (__, {viewMode}) => ( - + ); return Template; diff --git a/src/stories/components/DynamicField/DynamicField.tsx b/src/stories/components/DynamicField/DynamicField.tsx index ab7f22b0..67f083dd 100644 --- a/src/stories/components/DynamicField/DynamicField.tsx +++ b/src/stories/components/DynamicField/DynamicField.tsx @@ -16,9 +16,15 @@ export interface DynamicFieldProps { name: string; spec: Spec; search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean); + parseJsonDefaultValue?: boolean; } -export const DynamicField: React.FC = ({name, spec, search}) => { +export const DynamicField: React.FC = ({ + name, + spec, + search, + parseJsonDefaultValue = true, +}) => { const config = React.useMemo(() => { const cfg = _.cloneDeep(dynamicConfig); @@ -30,7 +36,7 @@ export const DynamicField: React.FC = ({name, spec, search}) return ( = ({spec: externalSpec, value, viewMode}) => { const [spec, setSpec] = React.useState(externalSpec); + const [ready, setReady] = React.useState(true); const [toggler, setToggler] = React.useState<'form' | 'view' | 'json'>('form'); const togglerItems = React.useMemo( @@ -45,6 +46,14 @@ export const Editor: React.FC = ({spec: externalSpec, value, viewMo [setToggler], ); + const handleSetSpec = React.useCallback( + (value: Spec) => { + setReady(false); + setSpec(value); + }, + [setSpec, setReady], + ); + const specEditorProps = React.useMemo( () => ({ @@ -52,7 +61,9 @@ export const Editor: React.FC = ({spec: externalSpec, value, viewMo value: JSON.stringify(spec, null, 2), onChange: (value) => { try { - setSpec(JSON.parse(value as string)); + const spec = JSON.parse(value as string); + + handleSetSpec(spec); } catch (_) {} }, }, @@ -93,6 +104,12 @@ export const Editor: React.FC = ({spec: externalSpec, value, viewMo [], ); + React.useEffect(() => { + if (!ready) { + setReady(true); + } + }, [ready]); + return (
@@ -115,9 +132,15 @@ export const Editor: React.FC = ({spec: externalSpec, value, viewMo {(form) => ( -
- -
+ {ready ? ( +
+ +
+ ) : null}
diff --git a/src/stories/components/InputPreview/SpecSelector.tsx b/src/stories/components/InputPreview/SpecSelector.tsx index ebe1ef7d..9eaf62ef 100644 --- a/src/stories/components/InputPreview/SpecSelector.tsx +++ b/src/stories/components/InputPreview/SpecSelector.tsx @@ -62,12 +62,6 @@ export const SpecSelector: ObjectIndependentInput = (props) => { [props.input.onChange, props.input.name], ); - const parentOnUnmount = React.useCallback( - (childName: string) => - props.input.onChange((currentValue) => currentValue, {[childName]: false}), - [props.input.onChange], - ); - const typeSpec = React.useMemo( () => ({ type: SpecTypes.String, @@ -93,7 +87,7 @@ export const SpecSelector: ObjectIndependentInput = (props) => { spec={optionsSpec} name={`${props.name}.${type}`} parentOnChange={parentOnChange} - parentOnUnmount={parentOnUnmount} + parentOnUnmount={props.input.parentOnUnmount} key={`${props.name}.${type}`} />