@gravity-ui/dynamic-forms 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build/cjs/lib/core/components/Form/Controller.js +13 -3
  3. package/build/cjs/lib/core/components/Form/DynamicField.js +14 -5
  4. package/build/cjs/lib/core/components/Form/hooks/index.js +4 -0
  5. package/build/cjs/lib/core/components/Form/hooks/useComponents.js +2 -2
  6. package/build/cjs/lib/core/components/Form/hooks/useCreateSearchContext.js +9 -0
  7. package/build/cjs/lib/core/components/Form/hooks/useField.js +8 -8
  8. package/build/cjs/lib/core/components/Form/hooks/useSearch/index.js +4 -0
  9. package/build/cjs/lib/core/components/Form/hooks/useSearch/useSearch.css +9 -0
  10. package/build/cjs/lib/core/components/Form/hooks/useSearch/useSearch.js +22 -0
  11. package/build/cjs/lib/core/components/Form/hooks/useSearchContext.js +12 -0
  12. package/build/cjs/lib/core/components/Form/hooks/useSearchStore.js +38 -0
  13. package/build/cjs/lib/core/components/Form/hooks/useStore.js +5 -4
  14. package/build/cjs/lib/core/components/Form/hooks/useValidate.js +2 -2
  15. package/build/cjs/lib/core/components/Form/index.js +1 -1
  16. package/build/cjs/lib/core/components/Form/types/index.js +1 -0
  17. package/build/cjs/lib/core/components/Form/types/search.js +2 -0
  18. package/build/cjs/lib/core/components/Form/{helpers.js → utils/common.js} +2 -2
  19. package/build/cjs/lib/core/components/Form/utils/index.js +5 -0
  20. package/build/cjs/lib/core/components/Form/utils/search.js +19 -0
  21. package/build/cjs/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +4 -3
  22. package/build/cjs/lib/kit/components/Inputs/CardOneOf/CardOneOf.js +2 -1
  23. package/build/cjs/lib/kit/components/Inputs/ObjectBase/ObjectBase.js +11 -2
  24. package/build/cjs/lib/kit/components/Inputs/OneOf/OneOf.js +2 -1
  25. package/build/cjs/lib/kit/components/Inputs/OneOfCard/OneOfCard.js +2 -1
  26. package/build/cjs/lib/kit/components/Inputs/Secret/Secret.js +2 -1
  27. package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.css +10 -0
  28. package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +21 -10
  29. package/build/esm/lib/core/components/Form/Controller.d.ts +2 -1
  30. package/build/esm/lib/core/components/Form/Controller.js +13 -3
  31. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  32. package/build/esm/lib/core/components/Form/DynamicField.js +14 -5
  33. package/build/esm/lib/core/components/Form/hooks/index.d.ts +4 -0
  34. package/build/esm/lib/core/components/Form/hooks/index.js +4 -0
  35. package/build/esm/lib/core/components/Form/hooks/useComponents.js +1 -1
  36. package/build/esm/lib/core/components/Form/hooks/useCreateSearchContext.d.ts +3 -0
  37. package/build/esm/lib/core/components/Form/hooks/useCreateSearchContext.js +4 -0
  38. package/build/esm/lib/core/components/Form/hooks/useField.d.ts +2 -1
  39. package/build/esm/lib/core/components/Form/hooks/useField.js +3 -3
  40. package/build/esm/lib/core/components/Form/hooks/useSearch/index.d.ts +1 -0
  41. package/build/esm/lib/core/components/Form/hooks/useSearch/index.js +1 -0
  42. package/build/esm/lib/core/components/Form/hooks/useSearch/useSearch.css +9 -0
  43. package/build/esm/lib/core/components/Form/hooks/useSearch/useSearch.d.ts +4 -0
  44. package/build/esm/lib/core/components/Form/hooks/useSearch/useSearch.js +18 -0
  45. package/build/esm/lib/core/components/Form/hooks/useSearchContext.d.ts +1 -0
  46. package/build/esm/lib/core/components/Form/hooks/useSearchContext.js +7 -0
  47. package/build/esm/lib/core/components/Form/hooks/useSearchStore.d.ts +8 -0
  48. package/build/esm/lib/core/components/Form/hooks/useSearchStore.js +33 -0
  49. package/build/esm/lib/core/components/Form/hooks/useStore.d.ts +1 -0
  50. package/build/esm/lib/core/components/Form/hooks/useStore.js +2 -1
  51. package/build/esm/lib/core/components/Form/hooks/useValidate.js +1 -1
  52. package/build/esm/lib/core/components/Form/index.d.ts +1 -1
  53. package/build/esm/lib/core/components/Form/index.js +1 -1
  54. package/build/esm/lib/core/components/Form/types/context.d.ts +1 -0
  55. package/build/esm/lib/core/components/Form/types/index.d.ts +1 -0
  56. package/build/esm/lib/core/components/Form/types/index.js +1 -0
  57. package/build/esm/lib/core/components/Form/types/search.d.ts +8 -0
  58. package/build/esm/lib/core/components/Form/types/search.js +1 -0
  59. package/build/esm/lib/core/components/Form/{helpers.d.ts → utils/common.d.ts} +1 -1
  60. package/build/esm/lib/core/components/Form/{helpers.js → utils/common.js} +2 -2
  61. package/build/esm/lib/core/components/Form/utils/index.d.ts +2 -0
  62. package/build/esm/lib/core/components/Form/utils/index.js +2 -0
  63. package/build/esm/lib/core/components/Form/utils/search.d.ts +3 -0
  64. package/build/esm/lib/core/components/Form/utils/search.js +14 -0
  65. package/build/esm/lib/kit/components/Inputs/ArrayBase/ArrayBase.js +4 -3
  66. package/build/esm/lib/kit/components/Inputs/CardOneOf/CardOneOf.js +2 -1
  67. package/build/esm/lib/kit/components/Inputs/ObjectBase/ObjectBase.js +11 -2
  68. package/build/esm/lib/kit/components/Inputs/OneOf/OneOf.js +2 -1
  69. package/build/esm/lib/kit/components/Inputs/OneOfCard/OneOfCard.js +2 -1
  70. package/build/esm/lib/kit/components/Inputs/Secret/Secret.js +2 -1
  71. package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.css +10 -0
  72. package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +21 -10
  73. package/package.json +1 -1
@@ -1,14 +1,24 @@
1
1
  import _ from 'lodash';
2
2
  import { isCorrectSpec } from '../../helpers';
3
3
  import { useComponents, useDynamicFormsCtx, useField, useRender, useValidate } from './hooks';
4
- export const Controller = ({ spec, name, initialValue, parentOnChange, }) => {
4
+ import { useSearch } from './hooks/useSearch';
5
+ export const Controller = ({ spec, name, initialValue, parentOnChange, parentOnUnmount, }) => {
5
6
  const { tools } = useDynamicFormsCtx();
6
7
  const { inputEntity, Layout } = useComponents(spec);
7
8
  const render = useRender({ name, spec, inputEntity, Layout });
8
9
  const validate = useValidate(spec);
9
- const renderProps = useField({ name, initialValue, spec, validate, tools, parentOnChange });
10
+ const renderProps = useField({
11
+ name,
12
+ initialValue,
13
+ spec,
14
+ validate,
15
+ tools,
16
+ parentOnChange,
17
+ parentOnUnmount,
18
+ });
19
+ const withSearch = useSearch(spec, renderProps.input.value, name);
10
20
  if (_.isString(name) && isCorrectSpec(spec)) {
11
- return render(renderProps);
21
+ return withSearch(render(renderProps));
12
22
  }
13
23
  return null;
14
24
  };
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
3
  import { Spec } from '../../types';
4
- import { DynamicFormConfig } from './types';
4
+ import { DynamicFormConfig, FieldValue } from './types';
5
5
  export interface DynamicFieldProps {
6
6
  name: string;
7
7
  spec: Spec;
8
8
  config: DynamicFormConfig;
9
9
  Monaco?: React.ComponentType<MonacoEditorProps>;
10
+ search?: string | ((spec: Spec, input: FieldValue, name: string) => boolean);
10
11
  }
11
12
  export declare const DynamicField: React.FC<DynamicFieldProps>;
@@ -3,21 +3,30 @@ import _ from 'lodash';
3
3
  import { isValidElementType } from 'react-is';
4
4
  import { isCorrectSpec } from '../../helpers';
5
5
  import { Controller } from './Controller';
6
- import { isCorrectConfig } from './helpers';
7
- import { useCreateContext, useStore } from './hooks';
8
- export const DynamicField = ({ name, spec, config, Monaco }) => {
6
+ import { useCreateContext, useCreateSearchContext, useSearchStore, useStore } from './hooks';
7
+ import { getDefaultSearchFunction, isCorrectConfig } from './utils';
8
+ export const DynamicField = ({ name, spec, config, Monaco, search }) => {
9
9
  const DynamicFormsCtx = useCreateContext();
10
+ const SearchContext = useCreateSearchContext();
10
11
  const { tools, watcher } = useStore(name);
12
+ const { setField, removeField, isHiddenField } = useSearchStore(name);
11
13
  const context = React.useMemo(() => ({
12
14
  config,
13
15
  Monaco: isValidElementType(Monaco) ? Monaco : undefined,
14
16
  tools,
15
17
  }), [tools, config, Monaco]);
18
+ const searchContext = React.useMemo(() => ({
19
+ setField,
20
+ removeField,
21
+ isHiddenField,
22
+ searchFunction: _.isFunction(search) ? search : getDefaultSearchFunction(search),
23
+ }), [isHiddenField, removeField, search, setField]);
16
24
  const correctParams = React.useMemo(() => _.isString(name) && isCorrectSpec(spec) && isCorrectConfig(config), [name, spec, config]);
17
25
  if (correctParams) {
18
26
  return (React.createElement(DynamicFormsCtx.Provider, { value: context },
19
- React.createElement(Controller, { spec: spec, name: name, parentOnChange: null, initialValue: _.get(tools.initialValue, name) }),
20
- watcher));
27
+ React.createElement(SearchContext.Provider, { value: searchContext },
28
+ React.createElement(Controller, { spec: spec, name: name, parentOnChange: null, parentOnUnmount: null, initialValue: _.get(tools.initialValue, name) }),
29
+ watcher)));
21
30
  }
22
31
  return null;
23
32
  };
@@ -6,3 +6,7 @@ export * from './useRender';
6
6
  export * from './useStore';
7
7
  export * from './useValidate';
8
8
  export * from './useMonaco';
9
+ export * from './useSearchStore';
10
+ export * from './useSearchContext';
11
+ export * from './useSearch';
12
+ export * from './useCreateSearchContext';
@@ -6,3 +6,7 @@ export * from './useRender';
6
6
  export * from './useStore';
7
7
  export * from './useValidate';
8
8
  export * from './useMonaco';
9
+ export * from './useSearchStore';
10
+ export * from './useSearchContext';
11
+ export * from './useSearch';
12
+ export * from './useCreateSearchContext';
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { isValidElementType } from 'react-is';
4
4
  import { isCorrectSpec } from '../../../helpers';
5
- import { isCorrectConfig } from '../helpers';
5
+ import { isCorrectConfig } from '../utils';
6
6
  import { useDynamicFormsCtx } from './';
7
7
  export const useComponents = (spec) => {
8
8
  var _a, _b;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { SearchContext } from '../types';
3
+ export declare const useCreateSearchContext: () => React.Context<SearchContext>;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import _ from 'lodash';
3
+ const createContext = _.once(() => React.createContext({}));
4
+ export const useCreateSearchContext = () => createContext();
@@ -7,5 +7,6 @@ export interface FieldProps<Value extends FieldValue, SpecType extends Spec> {
7
7
  validate?: (value?: Value) => ValidateError;
8
8
  tools: DynamicFormsContext['tools'];
9
9
  parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
10
+ parentOnUnmount: ((childName: string) => void) | null;
10
11
  }
11
- export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, }: FieldProps<Value, SpecType>) => FieldRenderProps<Value>;
12
+ export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }: FieldProps<Value, SpecType>) => FieldRenderProps<Value>;
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { isArraySpec, isObjectSpec } from '../../../helpers';
4
4
  import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM } from '../constants';
5
- import { isArrayItem, transformArrIn, transformArrOut } from '../helpers';
6
- export const useField = ({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, }) => {
5
+ import { isArrayItem, transformArrIn, transformArrOut } from '../utils';
6
+ export const useField = ({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }) => {
7
7
  const firstRenderRef = React.useRef(true);
8
8
  const validate = React.useCallback((value) => {
9
9
  if (value === REMOVED_ITEM) {
@@ -129,7 +129,7 @@ export const useField = ({ name, spec, initialValue, validate: propsValidate, to
129
129
  React.useEffect(() => {
130
130
  firstRenderRef.current = false;
131
131
  return () => {
132
- (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, { [name]: false });
132
+ (parentOnUnmount ? parentOnUnmount : tools.onUnmount)(name);
133
133
  };
134
134
  }, []);
135
135
  return renderProps;
@@ -0,0 +1 @@
1
+ export * from './useSearch';
@@ -0,0 +1 @@
1
+ export * from './useSearch';
@@ -0,0 +1,9 @@
1
+ .df-use-search {
2
+ margin-bottom: 15px;
3
+ }
4
+ .df-use-search_hidden {
5
+ display: none;
6
+ }
7
+ .df-use-search:last-child {
8
+ margin-bottom: 0;
9
+ }
@@ -0,0 +1,4 @@
1
+ import { Spec } from '../../../../types';
2
+ import { FieldValue } from '../../types';
3
+ import './useSearch.css';
4
+ export declare const useSearch: (spec: Spec, value: FieldValue, name: string) => (children: JSX.Element | null) => JSX.Element;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { block } from '../../../../../kit/utils';
3
+ import { useSearchContext } from '../useSearchContext';
4
+ import './useSearch.css';
5
+ const b = block('use-search');
6
+ export const useSearch = (spec, value, name) => {
7
+ const { setField, removeField, isHiddenField, searchFunction } = useSearchContext();
8
+ const searchResult = React.useMemo(() => !searchFunction(spec, value, name), [name, searchFunction, spec, value]);
9
+ const hidden = React.useMemo(() => isHiddenField(name), [isHiddenField, name]);
10
+ const withSearch = React.useCallback((children) => React.createElement("div", { className: b({ hidden: hidden }) }, children), [hidden]);
11
+ React.useEffect(() => {
12
+ setField(name, searchResult);
13
+ }, [searchResult]);
14
+ React.useEffect(() => {
15
+ return () => removeField(name);
16
+ }, []);
17
+ return withSearch;
18
+ };
@@ -0,0 +1 @@
1
+ export declare const useSearchContext: () => import("..").SearchContext;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { useCreateSearchContext } from './index';
3
+ export const useSearchContext = () => {
4
+ const SearchContext = useCreateSearchContext();
5
+ const context = React.useContext(SearchContext);
6
+ return context;
7
+ };
@@ -0,0 +1,8 @@
1
+ export declare const useSearchStore: (name: string) => {
2
+ store: {
3
+ [x: string]: boolean;
4
+ };
5
+ setField: (name: string, search: boolean) => void;
6
+ removeField: (name: string) => void;
7
+ isHiddenField: (name: string) => boolean;
8
+ };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import _ from 'lodash';
3
+ import { getParentName } from '../';
4
+ export const useSearchStore = (name) => {
5
+ const [store, setStore] = React.useState({ [name]: false });
6
+ const isHiddenField = React.useCallback((name) => {
7
+ const selfFlag = store[name];
8
+ if (selfFlag === false) {
9
+ return false;
10
+ }
11
+ let parentName = getParentName(name);
12
+ while (parentName) {
13
+ if (store[parentName] === false) {
14
+ return false;
15
+ }
16
+ parentName = getParentName(parentName);
17
+ }
18
+ for (const key of Object.keys(store)) {
19
+ if (key.includes(name + '.') && !store[key]) {
20
+ return false;
21
+ }
22
+ }
23
+ return true;
24
+ }, [store]);
25
+ return {
26
+ store,
27
+ setField: (name, search) => setStore((store) => (Object.assign(Object.assign({}, store), { [name]: search }))),
28
+ removeField: (name) => {
29
+ setStore((store) => _.omit(store, name));
30
+ },
31
+ isHiddenField,
32
+ };
33
+ };
@@ -9,6 +9,7 @@ export declare const useStore: (name: string) => {
9
9
  tools: {
10
10
  initialValue: FieldObjectValue;
11
11
  onChange: (name: string, value: FieldValue, errors?: Record<string, ValidateError>) => void;
12
+ onUnmount: (name: string) => void;
12
13
  submitFailed: boolean;
13
14
  };
14
15
  watcher: JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { Field as FinalFormField, useForm } from 'react-final-form';
4
- import { transformArrIn, transformArrOut } from '../helpers';
4
+ import { transformArrIn, transformArrOut } from '../utils';
5
5
  export const useStore = (name) => {
6
6
  const form = useForm();
7
7
  const firstRenderRef = React.useRef(true);
@@ -46,6 +46,7 @@ export const useStore = (name) => {
46
46
  const tools = React.useMemo(() => ({
47
47
  initialValue: store.initialValue,
48
48
  onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.set(Object.assign({}, store.values), name, value), errors: errors || {} }))),
49
+ onUnmount: (name) => setStore((store) => (Object.assign(Object.assign({}, store), { errors: _.omit(store.errors, Object.keys(store.errors).filter((key) => key.startsWith(name))) }))),
49
50
  submitFailed,
50
51
  }), [store.initialValue, setStore, submitFailed]);
51
52
  const change = React.useCallback(_.debounce((value) => {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { isCorrectSpec } from '../../../helpers';
4
- import { isCorrectConfig } from '../helpers';
4
+ import { isCorrectConfig } from '../utils';
5
5
  import { useDynamicFormsCtx } from './';
6
6
  export const useValidate = (spec) => {
7
7
  const { config } = useDynamicFormsCtx();
@@ -1,5 +1,5 @@
1
1
  export * from './constants';
2
2
  export * from './Controller';
3
3
  export * from './DynamicField';
4
- export * from './helpers';
5
4
  export * from './types';
5
+ export * from './utils';
@@ -1,5 +1,5 @@
1
1
  export * from './constants';
2
2
  export * from './Controller';
3
3
  export * from './DynamicField';
4
- export * from './helpers';
5
4
  export * from './types';
5
+ export * from './utils';
@@ -7,6 +7,7 @@ export interface DynamicFormsContext {
7
7
  tools: {
8
8
  initialValue: FieldObjectValue;
9
9
  onChange: (name: string, value: FieldValue, errors?: Record<string, ValidateError>) => void;
10
+ onUnmount: (name: string) => void;
10
11
  submitFailed: boolean;
11
12
  };
12
13
  }
@@ -10,3 +10,4 @@ export * from './object';
10
10
  export * from './string';
11
11
  export * from './validators';
12
12
  export * from './value';
13
+ export * from './search';
@@ -10,3 +10,4 @@ export * from './object';
10
10
  export * from './string';
11
11
  export * from './validators';
12
12
  export * from './value';
13
+ export * from './search';
@@ -0,0 +1,8 @@
1
+ import { Spec } from '../../../types';
2
+ import { FieldValue } from './value';
3
+ export interface SearchContext {
4
+ setField: (name: string, search: boolean) => void;
5
+ removeField: (name: string) => void;
6
+ isHiddenField: (name: string) => boolean;
7
+ searchFunction: (spec: Spec, value: FieldValue, name: string) => boolean;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import { FormValue } from '../../types';
1
+ import { FormValue } from '../../../types';
2
2
  export declare const isCorrectConfig: (candidate: any) => boolean;
3
3
  export declare const transformArrIn: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
4
4
  export declare const transformArrOut: <Type extends FormValue, ReturnType_1 extends FormValue = Type>(value: Type) => ReturnType_1;
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
- import { SpecTypes } from '../../constants';
3
- import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM } from './constants';
2
+ import { SpecTypes } from '../../../constants';
3
+ import { OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM } from '../constants';
4
4
  export const isCorrectConfig = (candidate) => Object.values(SpecTypes).every((type) => _.isObjectLike(candidate) &&
5
5
  _.isObjectLike(candidate[type]) &&
6
6
  _.isObjectLike(candidate[type].inputs) &&
@@ -0,0 +1,2 @@
1
+ export * from './common';
2
+ export * from './search';
@@ -0,0 +1,2 @@
1
+ export * from './common';
2
+ export * from './search';
@@ -0,0 +1,3 @@
1
+ import { Spec } from '../../../types';
2
+ export declare const getParentName: (name: string) => string | undefined;
3
+ export declare const getDefaultSearchFunction: (search?: string) => (spec: Spec) => boolean;
@@ -0,0 +1,14 @@
1
+ export const getParentName = (name) => {
2
+ const index = name.lastIndexOf('.');
3
+ if (index !== -1) {
4
+ return name.substring(0, index);
5
+ }
6
+ return undefined;
7
+ };
8
+ export const getDefaultSearchFunction = (search) => (spec) => {
9
+ var _a;
10
+ if (search) {
11
+ return Boolean((_a = spec.viewSpec.layoutTitle) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search.trim().toLowerCase()));
12
+ }
13
+ return true;
14
+ };
@@ -16,7 +16,7 @@ export const ArrayBase = ({ spec, name, arrayInput, input }) => {
16
16
  let item;
17
17
  if (!((_a = spec.items) === null || _a === void 0 ? void 0 : _a.required)) {
18
18
  if (isArraySpec(spec.items)) {
19
- item = { OBJECT_ARRAY_FLAG: true, OBJECT_ARRAY_CNT: 0 };
19
+ item = { [OBJECT_ARRAY_FLAG]: true, [OBJECT_ARRAY_CNT]: 0 };
20
20
  }
21
21
  else if (isObjectSpec(spec.items)) {
22
22
  item = {};
@@ -35,14 +35,15 @@ export const ArrayBase = ({ spec, name, arrayInput, input }) => {
35
35
  return itemSpec;
36
36
  }, [spec.items, itemSpecCorrect]);
37
37
  const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
38
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
38
39
  const items = React.useMemo(() => keys.map((key, idx) => {
39
40
  var _a;
40
41
  const itemSpec = getItemSpec(idx);
41
42
  if (!itemSpec) {
42
43
  return null;
43
44
  }
44
- return (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
45
- }), [keys.join(''), name, getItemSpec, parentOnChange, input.value]);
45
+ return (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[`<${key}>`], parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, spec: itemSpec, name: `${name}.<${key}>`, key: `${name}.<${key}>` }));
46
+ }), [keys.join(''), name, getItemSpec, parentOnChange, parentOnUnmount, input.value]);
46
47
  if (!itemSpecCorrect) {
47
48
  return null;
48
49
  }
@@ -26,6 +26,7 @@ export const CardOneOf = (props) => {
26
26
  const value = _.set({}, childName.split(`${input.name}.`).join(''), childValue);
27
27
  input.onChange(value, childErrors);
28
28
  }, [input.onChange, input.name]);
29
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
29
30
  useErrorChecker({ name, meta, open, setOpen });
30
- return (React.createElement(Card, { title: toggler, description: spec.viewSpec.layoutDescription, actions: actions, open: open, onToggle: onToggle, disableHeaderToggle: true }, specProperties[oneOfValue] ? (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, key: `${name}.${oneOfValue}` })) : null));
31
+ return (React.createElement(Card, { title: toggler, description: spec.viewSpec.layoutDescription, actions: actions, open: open, onToggle: onToggle, disableHeaderToggle: true }, specProperties[oneOfValue] ? (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
31
32
  };
@@ -13,6 +13,7 @@ export const ObjectBase = (_a) => {
13
13
  spec.viewSpec.layoutTitle || null));
14
14
  }, [spec.defaultValue, spec.viewSpec.layoutTitle, restProps.input.onChange]);
15
15
  const parentOnChange = React.useCallback((childName, childValue, childErrors) => restProps.input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${restProps.input.name}.`).join(''), childValue), childErrors), [restProps.input.onChange, restProps.input.name]);
16
+ const parentOnUnmount = React.useCallback((childName) => restProps.input.onChange((currentValue) => currentValue, { [childName]: false }), [restProps.input.onChange]);
16
17
  const content = React.useMemo(() => {
17
18
  if (!_.isObjectLike(spec.properties) || !Object.keys(spec.properties || {}).length) {
18
19
  return null;
@@ -23,9 +24,17 @@ export const ObjectBase = (_a) => {
23
24
  const specProperties = Object.assign({}, spec.properties);
24
25
  return (React.createElement(React.Fragment, null, (spec.viewSpec.order || Object.keys(specProperties)).map((property) => {
25
26
  var _a;
26
- return specProperties[property] ? (React.createElement(Controller, { initialValue: (_a = restProps.input.value) === null || _a === void 0 ? void 0 : _a[property], spec: specProperties[property], name: `${name ? name + '.' : ''}${property}`, parentOnChange: parentOnChange, key: `${name ? name + '.' : ''}${property}` })) : null;
27
+ return specProperties[property] ? (React.createElement(Controller, { initialValue: (_a = restProps.input.value) === null || _a === void 0 ? void 0 : _a[property], spec: specProperties[property], name: `${name ? name + '.' : ''}${property}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name ? name + '.' : ''}${property}` })) : null;
27
28
  })));
28
- }, [spec.properties, spec.viewSpec.order, name, restProps.input.value, addBtn, parentOnChange]);
29
+ }, [
30
+ spec.properties,
31
+ spec.viewSpec.order,
32
+ name,
33
+ restProps.input.value,
34
+ addBtn,
35
+ parentOnChange,
36
+ parentOnUnmount,
37
+ ]);
29
38
  if (!Layout || !content) {
30
39
  return content;
31
40
  }
@@ -13,8 +13,9 @@ export const OneOf = (props) => {
13
13
  const value = _.set({}, childName.split(`${props.input.name}.`).join(''), childValue);
14
14
  props.input.onChange(value, childErrors);
15
15
  }, [props.input.onChange, props.input.name]);
16
+ const parentOnUnmount = React.useCallback((childName) => props.input.onChange((currentValue) => currentValue, { [childName]: false }), [props.input.onChange]);
16
17
  return (React.createElement("div", { className: b() },
17
18
  specProperties[oneOfValue] ? (React.createElement(GroupIndent, null,
18
- React.createElement(Controller, { initialValue: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${props.name}.${oneOfValue}`, parentOnChange: parentOnChange, key: `${props.name}.${oneOfValue}` }))) : null,
19
+ React.createElement(Controller, { initialValue: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${props.name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${props.name}.${oneOfValue}` }))) : null,
19
20
  React.createElement("div", { className: b('toggler') }, toggler)));
20
21
  };
@@ -34,6 +34,7 @@ export const OneOfCard = (props) => {
34
34
  const value = _.set({}, childName.split(`${input.name}.`).join(''), childValue);
35
35
  input.onChange(value, childErrors);
36
36
  }, [input.onChange, input.name]);
37
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
37
38
  useErrorChecker({ name, meta, open, setOpen });
38
- return (React.createElement(AccordeonCard, { className: b(), header: toggler, description: spec.viewSpec.layoutDescription || '', open: open, onToggle: onToggle, ignoreHeaderToggle: true, headerActionsTemplate: headerActionsTemplate }, specProperties[oneOfValue] ? (React.createElement(Controller, { initialValue: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, key: `${name}.${oneOfValue}` })) : null));
39
+ return (React.createElement(AccordeonCard, { className: b(), header: toggler, description: spec.viewSpec.layoutDescription || '', open: open, onToggle: onToggle, ignoreHeaderToggle: true, headerActionsTemplate: headerActionsTemplate }, specProperties[oneOfValue] ? (React.createElement(Controller, { initialValue: (_a = props.input.value) === null || _a === void 0 ? void 0 : _a[oneOfValue], spec: specProperties[oneOfValue], name: `${name}.${oneOfValue}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${oneOfValue}` })) : null));
39
40
  };
@@ -5,6 +5,7 @@ const SECRET_PROPERTY_NAME = 'raw';
5
5
  export const Secret = ({ spec, name, input }) => {
6
6
  var _a;
7
7
  const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
8
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
8
9
  if (!_.isObjectLike(spec.properties)) {
9
10
  return null;
10
11
  }
@@ -12,5 +13,5 @@ export const Secret = ({ spec, name, input }) => {
12
13
  if (!specProperties[SECRET_PROPERTY_NAME]) {
13
14
  return null;
14
15
  }
15
- return (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[SECRET_PROPERTY_NAME], spec: specProperties[SECRET_PROPERTY_NAME], name: `${name}.${SECRET_PROPERTY_NAME}`, parentOnChange: parentOnChange, key: `${name}.${SECRET_PROPERTY_NAME}` }));
16
+ return (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[SECRET_PROPERTY_NAME], spec: specProperties[SECRET_PROPERTY_NAME], name: `${name}.${SECRET_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount, key: `${name}.${SECRET_PROPERTY_NAME}` }));
16
17
  };
@@ -1,6 +1,16 @@
1
1
  .df-table-array__table {
2
2
  margin-bottom: 10px;
3
3
  }
4
+ .df-table-array__table .yc-table__cell {
5
+ border-bottom: 0px transparent;
6
+ }
7
+ .df-table-array__row .yc-table__cell {
8
+ border-bottom: 0px transparent;
9
+ border-top: 1px solid var(--yc-color-line-generic);
10
+ }
11
+ .df-table-array__row_hidden {
12
+ display: none;
13
+ }
4
14
  .df-table-array__cell .yc-text-input,
5
15
  .df-table-array__cell .yc-select-control,
6
16
  .df-table-array__cell .yc-select,
@@ -3,16 +3,21 @@ import { Plus, Xmark } from '@gravity-ui/icons';
3
3
  import { Button, Icon, Table } from '@gravity-ui/uikit';
4
4
  import _ from 'lodash';
5
5
  import { Controller, OBJECT_ARRAY_CNT, OBJECT_ARRAY_FLAG, REMOVED_ITEM, isArraySpec, isBooleanSpec, isObjectSpec, transformArrIn, } from '../../../../core';
6
+ import { useSearchContext } from '../../../../core/components/Form/hooks';
6
7
  import { block } from '../../../utils';
7
8
  import './TableArrayInput.css';
8
9
  const b = block('table-array');
9
10
  export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
11
+ const { isHiddenField } = useSearchContext();
10
12
  const keys = React.useMemo(() => Object.keys(arrayInput.value || {})
11
13
  .filter((k) => k !== OBJECT_ARRAY_FLAG &&
12
14
  k !== OBJECT_ARRAY_CNT &&
13
15
  arrayInput.value[k] !== REMOVED_ITEM)
14
16
  .map((k) => k.split('<').join('').split('>').join(''))
15
- .sort((a, b) => Number(a) - Number(b)), [arrayInput.value]);
17
+ .sort((a, b) => Number(a) - Number(b))
18
+ .map((key) => ({
19
+ key,
20
+ })), [arrayInput.value]);
16
21
  const onItemAdd = React.useCallback(() => {
17
22
  arrayInput.onItemAdd({});
18
23
  }, [arrayInput.onItemAdd]);
@@ -20,6 +25,7 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
20
25
  arrayInput.onItemRemove(key);
21
26
  }, [arrayInput.onItemRemove]);
22
27
  const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${input.name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
28
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
23
29
  const columns = React.useMemo(() => {
24
30
  const { items, viewSpec: { table }, } = spec;
25
31
  if (!(table === null || table === void 0 ? void 0 : table.length) || !isObjectSpec(items)) {
@@ -29,39 +35,44 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
29
35
  id: 'idx',
30
36
  name: '',
31
37
  sticky: 'left',
32
- template: (key, idx) => (React.createElement("div", { className: b('idx'), key: `idx-${key}` }, idx + 1)),
38
+ template: ({ key }, idx) => (React.createElement("div", { className: b('idx'), key: `idx-${key}` }, idx + 1)),
33
39
  };
34
40
  const removeColumn = {
35
41
  id: 'remove',
36
42
  name: '',
37
43
  sticky: 'right',
38
- template: (key) => (React.createElement(Button, { view: "flat", onClick: () => onItemRemove(key), key: `remove-${key}` },
44
+ template: ({ key }) => (React.createElement(Button, { view: "flat", onClick: () => onItemRemove(key), key: `remove-${key}` },
39
45
  React.createElement(Icon, { data: Xmark, size: 16 }))),
40
46
  };
41
47
  const columns = table.map(({ property, label }) => ({
42
48
  id: property,
43
49
  name: label,
44
- template: (key) => {
50
+ template: ({ key, }, idx) => {
45
51
  var _a, _b, _c;
46
52
  const entitySpec = (_a = items === null || items === void 0 ? void 0 : items.properties) === null || _a === void 0 ? void 0 : _a[property];
47
53
  if (!entitySpec) {
48
54
  return null;
49
55
  }
56
+ const preparedEntitySpec = Object.assign(Object.assign({}, entitySpec), { viewSpec: Object.assign(Object.assign({}, entitySpec.viewSpec), { layoutTitle: table.map(({ label }) => label).join(` ${idx + 1} `) + ` ${idx + 1}` }) });
50
57
  return (React.createElement("div", { className: b('cell', {
51
- bool: isBooleanSpec(entitySpec),
52
- arr: isArraySpec(entitySpec),
53
- obj: isObjectSpec(entitySpec),
58
+ bool: isBooleanSpec(preparedEntitySpec),
59
+ arr: isArraySpec(preparedEntitySpec),
60
+ obj: isObjectSpec(preparedEntitySpec),
54
61
  }), key: `${name}.<${key}>.${property}` },
55
- React.createElement(Controller, { initialValue: (_c = (_b = input.value) === null || _b === void 0 ? void 0 : _b[`<${key}>`]) === null || _c === void 0 ? void 0 : _c[property], spec: entitySpec, name: `${name}.<${key}>.${property}`, parentOnChange: parentOnChange })));
62
+ React.createElement(Controller, { initialValue: (_c = (_b = input.value) === null || _b === void 0 ? void 0 : _b[`<${key}>`]) === null || _c === void 0 ? void 0 : _c[property], spec: preparedEntitySpec, name: `${name}.<${key}>.${property}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount })));
56
63
  },
57
64
  }));
58
65
  return [idxColumn, ...columns, removeColumn];
59
- }, [name, spec, onItemRemove, parentOnChange, input.value]);
66
+ }, [name, spec, onItemRemove, parentOnChange, parentOnUnmount, input.value]);
67
+ const getRowClassNames = React.useCallback(({ key }) => {
68
+ const searchResult = isHiddenField(`${name}.<${key}>`);
69
+ return [b('row', { hidden: searchResult })];
70
+ }, [isHiddenField, name]);
60
71
  if (!columns) {
61
72
  return null;
62
73
  }
63
74
  return (React.createElement("div", { className: b() },
64
- keys.length ? (React.createElement(Table, { className: b('table'), data: keys, columns: columns, getRowId: (_, idx) => `${name}-${idx}`, verticalAlign: "top" })) : null,
75
+ keys.length ? (React.createElement(Table, { className: b('table'), data: keys, columns: columns, getRowId: (_, idx) => `${name}-${idx}`, verticalAlign: "top", getRowClassNames: getRowClassNames })) : null,
65
76
  !arrayInput.value && spec.defaultValue ? (React.createElement(Button, { onClick: () => input.onChange(transformArrIn(spec.defaultValue)), disabled: spec.viewSpec.disabled },
66
77
  React.createElement(Icon, { data: Plus, size: 14 }),
67
78
  spec.viewSpec.layoutTitle || null)) : (React.createElement(Button, { onClick: onItemAdd, disabled: spec.viewSpec.disabled },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",