@gravity-ui/dynamic-forms 1.2.0 → 1.3.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 (66) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build/cjs/lib/core/components/Form/Controller.js +9 -3
  3. package/build/cjs/lib/core/components/Form/DynamicField.js +11 -4
  4. package/build/cjs/lib/core/components/Form/hooks/index.js +3 -0
  5. package/build/cjs/lib/core/components/Form/hooks/useControllerMirror.js +19 -0
  6. package/build/cjs/lib/core/components/Form/hooks/useDynamicFieldMirror.js +22 -0
  7. package/build/cjs/lib/core/components/Form/hooks/useField.js +1 -1
  8. package/build/cjs/lib/core/components/Form/hooks/useIntegrationFF.js +46 -0
  9. package/build/cjs/lib/core/components/Form/hooks/useSearchStore.js +5 -2
  10. package/build/cjs/lib/core/components/Form/hooks/useStore.js +3 -35
  11. package/build/cjs/lib/core/components/Form/types/index.js +2 -0
  12. package/build/cjs/lib/core/components/Form/types/mirror.js +2 -0
  13. package/build/cjs/lib/core/components/Form/types/store.js +2 -0
  14. package/build/cjs/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
  15. package/build/cjs/lib/kit/components/Inputs/TextLink/TextLink.js +20 -0
  16. package/build/cjs/lib/kit/components/Inputs/TextLink/index.js +4 -0
  17. package/build/cjs/lib/kit/components/Inputs/index.js +1 -0
  18. package/build/cjs/lib/kit/components/Layouts/Row/Row.css +18 -10
  19. package/build/cjs/lib/kit/components/Layouts/Row/Row.js +4 -5
  20. package/build/cjs/lib/kit/components/Views/TextLinkView/TextLinkView.js +17 -0
  21. package/build/cjs/lib/kit/components/Views/TextLinkView/index.js +4 -0
  22. package/build/cjs/lib/kit/components/Views/index.js +1 -0
  23. package/build/cjs/lib/kit/constants/config.js +4 -0
  24. package/build/cjs/lib/kit/validators/validators.js +1 -2
  25. package/build/esm/lib/core/components/Form/Controller.js +9 -3
  26. package/build/esm/lib/core/components/Form/DynamicField.d.ts +2 -1
  27. package/build/esm/lib/core/components/Form/DynamicField.js +12 -5
  28. package/build/esm/lib/core/components/Form/hooks/index.d.ts +3 -0
  29. package/build/esm/lib/core/components/Form/hooks/index.js +3 -0
  30. package/build/esm/lib/core/components/Form/hooks/useControllerMirror.d.ts +2 -0
  31. package/build/esm/lib/core/components/Form/hooks/useControllerMirror.js +14 -0
  32. package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.d.ts +2 -0
  33. package/build/esm/lib/core/components/Form/hooks/useDynamicFieldMirror.js +17 -0
  34. package/build/esm/lib/core/components/Form/hooks/useField.d.ts +2 -2
  35. package/build/esm/lib/core/components/Form/hooks/useField.js +1 -1
  36. package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.d.ts +2 -0
  37. package/build/esm/lib/core/components/Form/hooks/useIntegrationFF.js +41 -0
  38. package/build/esm/lib/core/components/Form/hooks/useSearchStore.d.ts +2 -4
  39. package/build/esm/lib/core/components/Form/hooks/useSearchStore.js +5 -2
  40. package/build/esm/lib/core/components/Form/hooks/useStore.d.ts +2 -8
  41. package/build/esm/lib/core/components/Form/hooks/useStore.js +5 -37
  42. package/build/esm/lib/core/components/Form/types/context.d.ts +2 -1
  43. package/build/esm/lib/core/components/Form/types/index.d.ts +2 -0
  44. package/build/esm/lib/core/components/Form/types/index.js +2 -0
  45. package/build/esm/lib/core/components/Form/types/mirror.d.ts +17 -0
  46. package/build/esm/lib/core/components/Form/types/mirror.js +1 -0
  47. package/build/esm/lib/core/components/Form/types/store.d.ts +7 -0
  48. package/build/esm/lib/core/components/Form/types/store.js +1 -0
  49. package/build/esm/lib/kit/components/Inputs/TableArrayInput/TableArrayInput.js +3 -2
  50. package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.d.ts +2 -0
  51. package/build/esm/lib/kit/components/Inputs/TextLink/TextLink.js +15 -0
  52. package/build/esm/lib/kit/components/Inputs/TextLink/index.d.ts +1 -0
  53. package/build/esm/lib/kit/components/Inputs/TextLink/index.js +1 -0
  54. package/build/esm/lib/kit/components/Inputs/index.d.ts +1 -0
  55. package/build/esm/lib/kit/components/Inputs/index.js +1 -0
  56. package/build/esm/lib/kit/components/Layouts/Row/Row.css +18 -10
  57. package/build/esm/lib/kit/components/Layouts/Row/Row.js +4 -5
  58. package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.d.ts +2 -0
  59. package/build/esm/lib/kit/components/Views/TextLinkView/TextLinkView.js +12 -0
  60. package/build/esm/lib/kit/components/Views/TextLinkView/index.d.ts +1 -0
  61. package/build/esm/lib/kit/components/Views/TextLinkView/index.js +1 -0
  62. package/build/esm/lib/kit/components/Views/index.d.ts +1 -0
  63. package/build/esm/lib/kit/components/Views/index.js +1 -0
  64. package/build/esm/lib/kit/constants/config.js +5 -1
  65. package/build/esm/lib/kit/validators/validators.js +1 -2
  66. package/package.json +12 -4
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ export const useDynamicFieldMirror = (params, __mirror) => {
3
+ if (__mirror === null || __mirror === void 0 ? void 0 : __mirror.field) {
4
+ __mirror.field.useStore = params.useStore;
5
+ __mirror.field.useIntegrationFF = params.useIntegrationFF;
6
+ __mirror.field.useSearchStore = params.useSearchStore;
7
+ }
8
+ React.useEffect(() => {
9
+ return () => {
10
+ if (__mirror === null || __mirror === void 0 ? void 0 : __mirror.field) {
11
+ delete __mirror.field.useStore;
12
+ delete __mirror.field.useIntegrationFF;
13
+ delete __mirror.field.useSearchStore;
14
+ }
15
+ };
16
+ }, []);
17
+ };
@@ -1,6 +1,6 @@
1
1
  import { Spec } from '../../../types';
2
2
  import { DynamicFormsContext, FieldRenderProps, FieldValue, ValidateError } from '../types';
3
- export interface FieldProps<Value extends FieldValue, SpecType extends Spec> {
3
+ export interface UseFieldProps<Value extends FieldValue, SpecType extends Spec> {
4
4
  name: string;
5
5
  spec: SpecType;
6
6
  initialValue: Value;
@@ -9,4 +9,4 @@ export interface FieldProps<Value extends FieldValue, SpecType extends Spec> {
9
9
  parentOnChange: ((childName: string, childValue: FieldValue, childErrors: Record<string, ValidateError>) => void) | null;
10
10
  parentOnUnmount: ((childName: string) => void) | null;
11
11
  }
12
- export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }: FieldProps<Value, SpecType>) => FieldRenderProps<Value>;
12
+ export declare const useField: <Value extends FieldValue, SpecType extends Spec>({ name, spec, initialValue, validate: propsValidate, tools, parentOnChange, parentOnUnmount, }: UseFieldProps<Value, SpecType>) => FieldRenderProps<Value>;
@@ -122,7 +122,7 @@ export const useField = ({ name, spec, initialValue, validate: propsValidate, to
122
122
  onDrop,
123
123
  ]);
124
124
  React.useEffect(() => {
125
- if (!firstRenderRef.current || !_.isEqual(initialValue, state.value)) {
125
+ if (!firstRenderRef.current || !_.isEqual(initialValue, state.value) || state.error) {
126
126
  (parentOnChange ? parentOnChange : tools.onChange)(name, state.value, Object.assign(Object.assign({}, state.childErrors), { [name]: state.error }));
127
127
  }
128
128
  }, [state.value]);
@@ -0,0 +1,2 @@
1
+ import { DynamicFieldStore } from '../types';
2
+ export declare const useIntegrationFF: (store: DynamicFieldStore) => JSX.Element;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import _ from 'lodash';
3
+ import debounce from 'lodash/debounce';
4
+ import { Field as FinalFormField, useForm } from 'react-final-form';
5
+ import { transformArrOut } from '../utils';
6
+ export const useIntegrationFF = (store) => {
7
+ const form = useForm();
8
+ const watcher = React.useMemo(() => {
9
+ const props = {
10
+ name: store.name,
11
+ render: () => null,
12
+ subscription: {},
13
+ validate: () => {
14
+ const asyncErrors = [];
15
+ let error;
16
+ _.values(store.errors).forEach((err) => {
17
+ if (err) {
18
+ if (_.isFunction(err === null || err === void 0 ? void 0 : err.then)) {
19
+ asyncErrors.push(err);
20
+ }
21
+ else {
22
+ error = err;
23
+ }
24
+ }
25
+ });
26
+ if (asyncErrors.length) {
27
+ return Promise.all(asyncErrors).then((r) => r[0]);
28
+ }
29
+ return error;
30
+ },
31
+ };
32
+ return React.createElement(FinalFormField, Object.assign({}, props));
33
+ }, [store.name, store.errors]);
34
+ const change = React.useCallback(debounce((value) => {
35
+ form.change(store.name, _.get(transformArrOut(value), store.name));
36
+ }, 100), [form.change, store.name]);
37
+ React.useEffect(() => {
38
+ change(store.values);
39
+ }, [store.values]);
40
+ return watcher;
41
+ };
@@ -1,7 +1,5 @@
1
- export declare const useSearchStore: (name: string) => {
2
- store: {
3
- [x: string]: boolean;
4
- };
1
+ export declare const useSearchStore: () => {
2
+ store: Record<string, boolean>;
5
3
  setField: (name: string, search: boolean) => void;
6
4
  removeField: (name: string) => void;
7
5
  isHiddenField: (name: string) => boolean;
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
3
  import { getParentName } from '../';
4
- export const useSearchStore = (name) => {
5
- const [store, setStore] = React.useState({ [name]: false });
4
+ export const useSearchStore = () => {
5
+ const [store, setStore] = React.useState({});
6
6
  const isHiddenField = React.useCallback((name) => {
7
7
  const selfFlag = store[name];
8
8
  if (selfFlag === false) {
@@ -20,6 +20,9 @@ export const useSearchStore = (name) => {
20
20
  return false;
21
21
  }
22
22
  }
23
+ if (_.isUndefined(selfFlag)) {
24
+ return false;
25
+ }
23
26
  return true;
24
27
  }, [store]);
25
28
  return {
@@ -1,10 +1,4 @@
1
- import { FieldObjectValue, FieldValue, ValidateError } from '../types';
2
- export interface DynamicFieldStore {
3
- name: string;
4
- initialValue: FieldObjectValue;
5
- values: FieldObjectValue;
6
- errors: Record<string, ValidateError>;
7
- }
1
+ import { DynamicFieldStore, FieldObjectValue, FieldValue, ValidateError } from '../types';
8
2
  export declare const useStore: (name: string) => {
9
3
  tools: {
10
4
  initialValue: FieldObjectValue;
@@ -12,5 +6,5 @@ export declare const useStore: (name: string) => {
12
6
  onUnmount: (name: string) => void;
13
7
  submitFailed: boolean;
14
8
  };
15
- watcher: JSX.Element;
9
+ store: DynamicFieldStore;
16
10
  };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import _ from 'lodash';
3
- import { Field as FinalFormField, useForm } from 'react-final-form';
4
- import { transformArrIn, transformArrOut } from '../utils';
3
+ import { useForm } from 'react-final-form';
4
+ import { transformArrIn } from '../utils';
5
5
  export const useStore = (name) => {
6
6
  const form = useForm();
7
7
  const firstRenderRef = React.useRef(true);
@@ -17,44 +17,12 @@ export const useStore = (name) => {
17
17
  };
18
18
  });
19
19
  const submitFailed = form.getState().submitFailed;
20
- const watcher = React.useMemo(() => {
21
- const props = {
22
- name: store.name,
23
- render: () => null,
24
- subscription: {},
25
- validate: () => {
26
- const asyncErrors = [];
27
- let error;
28
- _.values(store.errors).forEach((err) => {
29
- if (err) {
30
- if (_.isFunction(err === null || err === void 0 ? void 0 : err.then)) {
31
- asyncErrors.push(err);
32
- }
33
- else {
34
- error = err;
35
- }
36
- }
37
- });
38
- if (asyncErrors.length) {
39
- return Promise.all(asyncErrors).then((r) => r[0]);
40
- }
41
- return error;
42
- },
43
- };
44
- return React.createElement(FinalFormField, Object.assign({}, props));
45
- }, [store.name, store.errors]);
46
20
  const tools = React.useMemo(() => ({
47
21
  initialValue: store.initialValue,
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))) }))),
22
+ onChange: (name, value, errors) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.set(Object.assign({}, store.values), name, _.clone(value)), errors: errors || {} }))),
23
+ onUnmount: (name) => setStore((store) => (Object.assign(Object.assign({}, store), { values: _.omit(store.values, name), errors: _.omit(store.errors, Object.keys(store.errors).filter((key) => key.startsWith(name))) }))),
50
24
  submitFailed,
51
25
  }), [store.initialValue, setStore, submitFailed]);
52
- const change = React.useCallback(_.debounce((value) => {
53
- form.change(store.name, _.get(transformArrOut(value), store.name));
54
- }, 100), [form.change, store.name]);
55
- React.useEffect(() => {
56
- change(store.values);
57
- }, [store.values]);
58
26
  React.useEffect(() => {
59
27
  if (!firstRenderRef.current) {
60
28
  const initialValue = transformArrIn({
@@ -71,5 +39,5 @@ export const useStore = (name) => {
71
39
  React.useEffect(() => {
72
40
  firstRenderRef.current = false;
73
41
  }, []);
74
- return { tools, watcher };
42
+ return { tools, store };
75
43
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { MonacoEditorProps } from 'react-monaco-editor/lib/types';
3
- import { DynamicFormConfig, FieldObjectValue, FieldValue, ValidateError } from './';
3
+ import { DynamicFormConfig, FieldObjectValue, FieldValue, ValidateError, WonderMirror } from './';
4
4
  export interface DynamicFormsContext {
5
5
  config: DynamicFormConfig;
6
6
  Monaco?: React.ComponentType<MonacoEditorProps>;
@@ -10,4 +10,5 @@ export interface DynamicFormsContext {
10
10
  onUnmount: (name: string) => void;
11
11
  submitFailed: boolean;
12
12
  };
13
+ __mirror?: WonderMirror;
13
14
  }
@@ -5,8 +5,10 @@ export * from './context';
5
5
  export * from './field';
6
6
  export * from './input';
7
7
  export * from './layout';
8
+ export * from './mirror';
8
9
  export * from './number';
9
10
  export * from './object';
11
+ export * from './store';
10
12
  export * from './string';
11
13
  export * from './validators';
12
14
  export * from './value';
@@ -5,8 +5,10 @@ export * from './context';
5
5
  export * from './field';
6
6
  export * from './input';
7
7
  export * from './layout';
8
+ export * from './mirror';
8
9
  export * from './number';
9
10
  export * from './object';
11
+ export * from './store';
10
12
  export * from './string';
11
13
  export * from './validators';
12
14
  export * from './value';
@@ -0,0 +1,17 @@
1
+ import { useComponents, useField, useIntegrationFF, useRender, useSearch, useSearchStore, useStore, useValidate } from '../hooks';
2
+ export interface ControllerMirror {
3
+ useComponents?: ReturnType<typeof useComponents>;
4
+ useRender?: ReturnType<typeof useRender>;
5
+ useValidate?: ReturnType<typeof useValidate>;
6
+ useField?: ReturnType<typeof useField>;
7
+ useSearch?: ReturnType<typeof useSearch>;
8
+ }
9
+ export interface DynamicFieldMirror {
10
+ useStore?: ReturnType<typeof useStore>;
11
+ useIntegrationFF?: ReturnType<typeof useIntegrationFF>;
12
+ useSearchStore?: ReturnType<typeof useSearchStore>;
13
+ }
14
+ export interface WonderMirror {
15
+ field: DynamicFieldMirror;
16
+ controller: Record<string, ControllerMirror | undefined>;
17
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { FieldObjectValue, ValidateError } from '../types';
2
+ export interface DynamicFieldStore {
3
+ name: string;
4
+ initialValue: FieldObjectValue;
5
+ values: FieldObjectValue;
6
+ errors: Record<string, ValidateError>;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -65,9 +65,10 @@ export const TableArrayInput = ({ spec, name, arrayInput, input }) => {
65
65
  return [idxColumn, ...columns, removeColumn];
66
66
  }, [name, spec, onItemRemove, parentOnChange, parentOnUnmount, input.value]);
67
67
  const getRowClassNames = React.useCallback(({ key }) => {
68
- const searchResult = isHiddenField(`${name}.<${key}>`);
68
+ var _a;
69
+ const searchResult = (_a = spec.viewSpec.table) === null || _a === void 0 ? void 0 : _a.every(({ property }) => isHiddenField(`${name}.<${key}>.${property}`));
69
70
  return [b('row', { hidden: searchResult })];
70
- }, [isHiddenField, name]);
71
+ }, [isHiddenField, name, spec.viewSpec.table]);
71
72
  if (!columns) {
72
73
  return null;
73
74
  }
@@ -0,0 +1,2 @@
1
+ import { ObjectIndependentInput } from '../../../../core';
2
+ export declare const TextLink: ObjectIndependentInput;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import _ from 'lodash';
3
+ import { Controller, isStringSpec, } from '../../../../core';
4
+ const TEXT_LINK_PROPERTY_NAME = 'text';
5
+ export const TextLink = ({ spec, input, name }) => {
6
+ var _a;
7
+ const parentOnChange = React.useCallback((childName, childValue, childErrors) => input.onChange((currentValue) => _.set(Object.assign({}, currentValue), childName.split(`${name}.`).join(''), childValue), childErrors), [input.onChange, input.name]);
8
+ const parentOnUnmount = React.useCallback((childName) => input.onChange((currentValue) => currentValue, { [childName]: false }), [input.onChange]);
9
+ const specProperties = Object.assign({}, spec.properties);
10
+ if (!specProperties[TEXT_LINK_PROPERTY_NAME] ||
11
+ !isStringSpec(specProperties[TEXT_LINK_PROPERTY_NAME])) {
12
+ return null;
13
+ }
14
+ return (React.createElement(Controller, { initialValue: (_a = input.value) === null || _a === void 0 ? void 0 : _a[TEXT_LINK_PROPERTY_NAME], spec: specProperties[TEXT_LINK_PROPERTY_NAME], name: `${name}.${TEXT_LINK_PROPERTY_NAME}`, key: `${name}.${TEXT_LINK_PROPERTY_NAME}`, parentOnChange: parentOnChange, parentOnUnmount: parentOnUnmount }));
15
+ };
@@ -0,0 +1 @@
1
+ export * from './TextLink';
@@ -0,0 +1 @@
1
+ export * from './TextLink';
@@ -11,5 +11,6 @@ export * from './TableArrayInput';
11
11
  export * from './Text';
12
12
  export * from './TextArea';
13
13
  export * from './TextContent';
14
+ export * from './TextLink';
14
15
  export * from './NumberWithScale';
15
16
  export * from './MonacoInput';
@@ -11,5 +11,6 @@ export * from './TableArrayInput';
11
11
  export * from './Text';
12
12
  export * from './TextArea';
13
13
  export * from './TextContent';
14
+ export * from './TextLink';
14
15
  export * from './NumberWithScale';
15
16
  export * from './MonacoInput';
@@ -13,13 +13,16 @@
13
13
  }
14
14
  .df-row__left {
15
15
  width: 180px;
16
+ min-height: 28px;
16
17
  display: flex;
18
+ margin-bottom: auto;
17
19
  flex-direction: column;
18
20
  flex-shrink: 0;
19
21
  }
20
22
  .df-row__left-inner {
21
- min-height: 28px;
22
- display: flex;
23
+ display: inline;
24
+ margin-top: auto;
25
+ margin-bottom: auto;
23
26
  }
24
27
  .df-row__left::after {
25
28
  content: "";
@@ -27,18 +30,24 @@
27
30
  flex-shrink: 1;
28
31
  }
29
32
  .df-row__title {
30
- align-self: center;
33
+ word-break: break-word;
34
+ margin-right: 3px;
35
+ }
36
+ .df-row__title_required::after {
37
+ content: "*";
38
+ color: var(--yc-color-text-danger);
31
39
  }
32
40
  .df-row__note {
33
- height: 28px;
34
- display: flex;
35
- align-items: center;
36
- margin-left: 5px;
41
+ padding-right: 16px;
42
+ }
43
+ .df-row__note-inner {
44
+ position: absolute;
45
+ margin-top: 1px;
37
46
  }
38
- .df-row__note .yc-help-popover {
47
+ .df-row__note-inner .yc-help-popover {
39
48
  display: flex;
40
49
  }
41
- .df-row__note .yc-help-popover > span {
50
+ .df-row__note-inner .yc-help-popover > span {
42
51
  display: flex;
43
52
  }
44
53
  .df-row__right {
@@ -59,6 +68,5 @@
59
68
  margin-left: 5px;
60
69
  }
61
70
  .df-row__required-mark {
62
- margin-left: 2px;
63
71
  color: var(--yc-color-text-danger);
64
72
  }
@@ -11,11 +11,10 @@ const RowBase = ({ name, spec, input, meta, verboseDescription, children, }) =>
11
11
  return (React.createElement("div", { className: b({ 'extra-width': isArraySpec(spec) || arrayItem }) },
12
12
  React.createElement("div", { className: b('left') },
13
13
  React.createElement("div", { className: b('left-inner') },
14
- React.createElement("div", { className: b('title') },
15
- spec.viewSpec.layoutTitle,
16
- spec.required && React.createElement("span", { className: b('required-mark') }, "*")),
17
- !verboseDescription && spec.viewSpec.layoutDescription ? (React.createElement("div", { className: b('note') },
18
- React.createElement(HelpPopover, { htmlContent: spec.viewSpec.layoutDescription, placement: ['bottom', 'top'] }))) : null)),
14
+ React.createElement("span", { className: b('title', { required: spec.required }) }, spec.viewSpec.layoutTitle),
15
+ !verboseDescription && spec.viewSpec.layoutDescription ? (React.createElement("span", { className: b('note') },
16
+ React.createElement("span", { className: b('note-inner') },
17
+ React.createElement(HelpPopover, { htmlContent: spec.viewSpec.layoutDescription, placement: ['bottom', 'top'] })))) : null)),
19
18
  React.createElement("div", { className: b('right') },
20
19
  React.createElement("div", { className: b('right-inner') },
21
20
  React.createElement(ErrorWrapper, { name: name, meta: meta, withoutChildErrorStyles: isArraySpec(spec) || isObjectSpec(spec) }, children),
@@ -0,0 +1,2 @@
1
+ import { ObjectIndependentView } from '../../../../core';
2
+ export declare const TextLinkView: ObjectIndependentView;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { ViewController } from '../../../../core';
3
+ const TEXT_LINK_PROPERTY_NAME = 'text';
4
+ export const TextLinkView = ({ value, spec, name }) => {
5
+ const specProperties = spec.properties;
6
+ const preparedSpec = React.useMemo(() => {
7
+ var _a;
8
+ return specProperties && specProperties[TEXT_LINK_PROPERTY_NAME]
9
+ ? Object.assign(Object.assign({}, specProperties[TEXT_LINK_PROPERTY_NAME]), { viewSpec: Object.assign(Object.assign({}, (_a = specProperties[TEXT_LINK_PROPERTY_NAME]) === null || _a === void 0 ? void 0 : _a.viewSpec), { link: value === null || value === void 0 ? void 0 : value.link }) }) : undefined;
10
+ }, [specProperties, value === null || value === void 0 ? void 0 : value.link]);
11
+ return preparedSpec ? (React.createElement(ViewController, { spec: preparedSpec, name: `${name}.${TEXT_LINK_PROPERTY_NAME}` })) : null;
12
+ };
@@ -0,0 +1 @@
1
+ export * from './TextLinkView';
@@ -0,0 +1 @@
1
+ export * from './TextLinkView';
@@ -9,3 +9,4 @@ export * from './OneOfCardView';
9
9
  export * from './OneOfView';
10
10
  export * from './TableArrayView';
11
11
  export * from './TextAreaView';
12
+ export * from './TextLinkView';
@@ -9,3 +9,4 @@ export * from './OneOfCardView';
9
9
  export * from './OneOfView';
10
10
  export * from './TableArrayView';
11
11
  export * from './TextAreaView';
12
+ export * from './TextLinkView';
@@ -1,4 +1,4 @@
1
- import { Accordeon, AccordeonCardLayout, ArrayBase, ArrayBaseView, BaseView, CardAccordeon, CardOneOf, CardOneOfView, CardSection, Checkbox, Group, Group2, MonacoInput, MonacoInputCard, MonacoView, MonacoViewCard, MultiSelect, MultiSelectView, NumberWithScale, NumberWithScaleView, ObjectBase, ObjectBaseView, OneOf, OneOfCard, OneOfCardView, OneOfView, Row, Row2, RowVerbose, Secret, Section, Section2, SectionCard, SectionCard2, SectionWithSubtitle, SectionWithSubtitle2, Select, TableArrayInput, TableArrayView, TableCell, Text, TextArea, TextAreaView, TextContent, Transparent, ViewAccordeon, ViewAccordeonCard, ViewCardAccordeon, ViewCardSection, ViewGroup, ViewGroup2, ViewRow, ViewRow2, ViewSection, ViewSection2, ViewSectionCard, ViewSectionCard2, ViewTableCell, ViewTransparent, } from '../components';
1
+ import { Accordeon, AccordeonCardLayout, ArrayBase, ArrayBaseView, BaseView, CardAccordeon, CardOneOf, CardOneOfView, CardSection, Checkbox, Group, Group2, MonacoInput, MonacoInputCard, MonacoView, MonacoViewCard, MultiSelect, MultiSelectView, NumberWithScale, NumberWithScaleView, ObjectBase, ObjectBaseView, OneOf, OneOfCard, OneOfCardView, OneOfView, Row, Row2, RowVerbose, Secret, Section, Section2, SectionCard, SectionCard2, SectionWithSubtitle, SectionWithSubtitle2, Select, TableArrayInput, TableArrayView, TableCell, Text, TextArea, TextAreaView, TextContent, TextLink, TextLinkView, Transparent, ViewAccordeon, ViewAccordeonCard, ViewCardAccordeon, ViewCardSection, ViewGroup, ViewGroup2, ViewRow, ViewRow2, ViewSection, ViewSection2, ViewSectionCard, ViewSectionCard2, ViewTableCell, ViewTransparent, } from '../components';
2
2
  import { getArrayValidator, getBooleanValidator, getNumberValidator, getObjectValidator, getStringValidator, } from '../validators';
3
3
  export const dynamicConfig = {
4
4
  array: {
@@ -57,6 +57,7 @@ export const dynamicConfig = {
57
57
  card_oneof: { Component: CardOneOf, independent: true },
58
58
  secret: { Component: Secret, independent: true },
59
59
  base: { Component: ObjectBase, independent: true },
60
+ text_link: { Component: TextLink, independent: true },
60
61
  },
61
62
  layouts: {
62
63
  row: Row,
@@ -152,6 +153,7 @@ export const dynamicCardConfig = {
152
153
  oneof: { Component: OneOfCard, independent: true },
153
154
  secret: { Component: Secret, independent: true },
154
155
  base: { Component: ObjectBase, independent: true },
156
+ text_link: { Component: TextLink, independent: true },
155
157
  },
156
158
  layouts: {
157
159
  row: Row2,
@@ -236,6 +238,7 @@ export const dynamicViewConfig = {
236
238
  card_oneof: { Component: CardOneOfView, independent: true },
237
239
  secret: undefined,
238
240
  base: { Component: ObjectBaseView, independent: true },
241
+ text_link: { Component: TextLinkView, independent: true },
239
242
  },
240
243
  layouts: {
241
244
  row: ViewRow,
@@ -313,6 +316,7 @@ export const dynamicViewCardConfig = {
313
316
  oneof: { Component: OneOfCardView, independent: true },
314
317
  secret: undefined,
315
318
  base: { Component: ObjectBaseView, independent: true },
319
+ text_link: { Component: TextLinkView, independent: true },
316
320
  },
317
321
  layouts: {
318
322
  row: ViewRow2,
@@ -65,8 +65,7 @@ export const getNumberValidator = (params = {}) => {
65
65
  }
66
66
  if (!ignoreMinimumCheck &&
67
67
  _.isNumber(spec.minimum) &&
68
- stringValue.length &&
69
- spec.minimum > Number(stringValue)) {
68
+ ((stringValue.length && spec.minimum > Number(stringValue)) || !stringValue.length)) {
70
69
  return ErrorMessages.minNumber(spec.minimum);
71
70
  }
72
71
  if (_.isString(spec.format) && stringValue.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/dynamic-forms",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "main": "build/cjs/index.js",
@@ -28,7 +28,8 @@
28
28
  "lint:js": "eslint src --quiet",
29
29
  "lint:prettier": "prettier --check 'src/**/*.{js,jsx,ts,tsx,css,scss}'",
30
30
  "lint:styles": "stylelint 'src/**/*.scss'",
31
- "typecheck": "tsc -p src --noEmit",
31
+ "test": "jest",
32
+ "typecheck": "tsc --noEmit",
32
33
  "build": "gulp",
33
34
  "build-storybook": "build-storybook",
34
35
  "dev": "start-storybook -p 6006",
@@ -42,10 +43,10 @@
42
43
  "lodash": "^4.17.20"
43
44
  },
44
45
  "devDependencies": {
45
- "@commitlint/cli": "^17.0.0",
46
- "@commitlint/config-conventional": "^17.0.0",
47
46
  "@babel/preset-env": "^7.20.2",
48
47
  "@babel/preset-typescript": "^7.18.6",
48
+ "@commitlint/cli": "^17.0.0",
49
+ "@commitlint/config-conventional": "^17.0.0",
49
50
  "@gravity-ui/eslint-config": "^2.0.0",
50
51
  "@gravity-ui/prettier-config": "^1.0.1",
51
52
  "@gravity-ui/stylelint-config": "^2.0.0",
@@ -54,6 +55,9 @@
54
55
  "@storybook/addon-essentials": "^6.5.16",
55
56
  "@storybook/preset-scss": "^1.0.3",
56
57
  "@storybook/react": "^6.5.16",
58
+ "@testing-library/jest-dom": "^5.16.5",
59
+ "@testing-library/react": "^14.0.0",
60
+ "@types/jest": "^29.5.0",
57
61
  "@types/lodash": "^4.14.180",
58
62
  "@types/react": "^18.0.28",
59
63
  "@types/react-dom": "^18.0.11",
@@ -67,6 +71,9 @@
67
71
  "gulp-replace": "^1.1.4",
68
72
  "gulp-typescript": "^6.0.0-alpha.1",
69
73
  "husky": "^7.0.4",
74
+ "jest": "^29.5.0",
75
+ "jest-environment-jsdom": "^29.5.0",
76
+ "jest-transform-css": "^6.0.1",
70
77
  "monaco-editor": "^0.30.1",
71
78
  "monaco-editor-webpack-plugin": "^6.0.0",
72
79
  "npm-run-all": "^4.1.5",
@@ -83,6 +90,7 @@
83
90
  "style-loader": "^2.0.0",
84
91
  "stylelint": "^14.15.0",
85
92
  "stylelint-scss": "^4.2.0",
93
+ "ts-jest": "^29.0.5",
86
94
  "typescript": "^4.9.5"
87
95
  },
88
96
  "peerDependencies": {