diff --git a/docs/spec.md b/docs/spec.md index 1cdd4f97..e44813e6 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -94,6 +94,7 @@ type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec; | viewSpec.oneOfParams | `object` | | [Parameters](#oneofparams) that must be passed to oneof input | | viewSpec.placeholder | `string` | | A short hint displayed in the field before the user enters the value | | viewSpec.hidden | `boolean` | | Hide field and view | +| viewSpec.delimiter | `Record` | | Values of delimiters of inline object input elements | ### StringSpec @@ -144,9 +145,10 @@ type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec; #### OneOfParams -| Property | Type | Required | Description | -| :------- | :---------------------------- | :------: | :---------- | -| toggler | `'select'` `'radio'` `'card'` | | Switch type | +| Property | Type | Required | Description | +| :--------- | :----------------------------------------- | :------: | :--------------------------------------------- | +| toggler | `'select'` `'radio'` `'card'` `'checkbox'` | | Switch type | +| booleanMap | `Record<'true' 'false', string>` | | Special object for oneof toggler type checkbox | #### FileInput diff --git a/src/lib/core/types/specs.ts b/src/lib/core/types/specs.ts index 732e6b4d..1cc7d328 100644 --- a/src/lib/core/types/specs.ts +++ b/src/lib/core/types/specs.ts @@ -118,12 +118,14 @@ export interface ObjectSpec< order?: string[]; link?: LinkType; oneOfParams?: { - toggler?: 'select' | 'radio' | 'card'; + toggler?: 'select' | 'radio' | 'card' | 'checkbox'; + booleanMap?: Record<'true' | 'false', string>; }; placeholder?: string; hidden?: boolean; inputProps?: InputComponentProps; layoutProps?: LayoutComponentProps; + delimiter?: Record; }; } diff --git a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.scss b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.scss index 106b008e..4f447549 100644 --- a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.scss +++ b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.scss @@ -16,4 +16,11 @@ } } } + + &__delimiter { + display: flex; + margin-right: 8px; + align-items: center; + white-space: nowrap; + } } diff --git a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx index 24349249..caf0a5bf 100644 --- a/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx +++ b/src/lib/kit/components/Inputs/ObjectBase/ObjectBase.tsx @@ -1,8 +1,9 @@ import React from 'react'; import {Plus} from '@gravity-ui/icons'; -import {Button, Icon} from '@gravity-ui/uikit'; -import _ from 'lodash'; +import {Button, Icon, Text} from '@gravity-ui/uikit'; +import isObjectLike from 'lodash/isObjectLike'; +import set from 'lodash/set'; import { Controller, @@ -53,7 +54,7 @@ export const ObjectBase: React.FC = ({ (childName: string, childValue: FieldValue, childErrors?: Record) => restProps.input.onChange( (currentValue) => - _.set( + set( {...currentValue}, childName.split(`${restProps.input.name}.`).join(''), childValue, @@ -66,7 +67,7 @@ export const ObjectBase: React.FC = ({ const content = React.useMemo(() => { if ( !spec.properties || - !_.isObjectLike(spec.properties) || + !isObjectLike(spec.properties) || !Object.keys(spec.properties || {}).length ) { return null; @@ -80,24 +81,32 @@ export const ObjectBase: React.FC = ({ ? filterPropertiesForObjectInline(spec.properties) : spec.properties; + const delimiter = spec.viewSpec.delimiter; + const orderProperties = spec.viewSpec.order || Object.keys(specProperties); + return (
- {(spec.viewSpec.order || Object.keys(specProperties)).map((property: string) => + {orderProperties.map((property: string) => specProperties[property] ? ( - + + + {delimiter && delimiter[property] ? ( + {delimiter[property]} + ) : null} + ) : null, )}
); }, [ spec.properties, + spec.viewSpec.delimiter, spec.viewSpec.order, restProps.input.value, restProps.input.parentOnUnmount, diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-chromium-linux.png new file mode 100644 index 00000000..98fc2b3e Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-webkit-linux.png new file mode 100644 index 00000000..d24c6713 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-chromium-linux.png new file mode 100644 index 00000000..5c3aa7ea Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-webkit-linux.png new file mode 100644 index 00000000..8c87520a Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-chromium-linux.png new file mode 100644 index 00000000..8c0b3898 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-webkit-linux.png new file mode 100644 index 00000000..12cc6400 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-chromium-linux.png new file mode 100644 index 00000000..1bfc65a6 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-webkit-linux.png new file mode 100644 index 00000000..cad48a35 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-delimiter-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-chromium-linux.png new file mode 100644 index 00000000..8dc163aa Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-webkit-linux.png new file mode 100644 index 00000000..e44c3e7f Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-chromium-linux.png new file mode 100644 index 00000000..6a08b11a Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-webkit-linux.png new file mode 100644 index 00000000..e7d9596f Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-chromium-linux.png new file mode 100644 index 00000000..216976a5 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-webkit-linux.png new file mode 100644 index 00000000..8fcf1a37 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-chromium-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-chromium-linux.png new file mode 100644 index 00000000..42d1d077 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-webkit-linux.png b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-webkit-linux.png new file mode 100644 index 00000000..b1981563 Binary files /dev/null and b/src/lib/kit/components/Inputs/ObjectBase/__snapshots__/ObjectBase.visual.test.tsx-snapshots/Object-Inline-view-delimiter-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/ObjectBase/__tests__/ObjectBase.visual.test.tsx b/src/lib/kit/components/Inputs/ObjectBase/__tests__/ObjectBase.visual.test.tsx index 080ee399..e31ca5d4 100644 --- a/src/lib/kit/components/Inputs/ObjectBase/__tests__/ObjectBase.visual.test.tsx +++ b/src/lib/kit/components/Inputs/ObjectBase/__tests__/ObjectBase.visual.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {OBJECT_BASE, VALUE} from './helpers'; +import {OBJECT_BASE, OBJECT_INLINE, VALUE, VALUE_INLINE} from './helpers'; import {test} from '~playwright/core'; import {DynamicForm} from '~playwright/core/DynamicForm'; @@ -75,8 +75,36 @@ test.describe('Object Base', () => { }); }); +test.describe('Object Inline', () => { + test('default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); + + test('delimiter', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); +}); + test('Object Base view', async ({mount, expectScreenshot}) => { await mount(); await expectScreenshot(); }); + +test.describe('Object Inline view', () => { + test('default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); + + test('delimiter', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); +}); diff --git a/src/lib/kit/components/Inputs/ObjectBase/__tests__/helpers.ts b/src/lib/kit/components/Inputs/ObjectBase/__tests__/helpers.ts index 157a309a..be53fa76 100644 --- a/src/lib/kit/components/Inputs/ObjectBase/__tests__/helpers.ts +++ b/src/lib/kit/components/Inputs/ObjectBase/__tests__/helpers.ts @@ -408,7 +408,73 @@ export const OBJECT_BASE: Record = { }, }; +export const OBJECT_INLINE: Record = { + default: { + type: SpecTypes.Object, + defaultValue: {type: 'first', name: 'Name'}, + properties: { + type: { + type: SpecTypes.String, + enum: ['first', 'second', 'third'], + viewSpec: { + type: 'select', + placeholder: 'Choose type', + layout: 'transparent', + layoutTitle: 'Type', + }, + }, + name: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + placeholder: 'Type your name', + layout: 'transparent', + layoutTitle: 'Name', + }, + }, + }, + viewSpec: { + type: 'inline', + layout: 'row', + layoutTitle: 'Candidate', + }, + }, + delimiter: { + type: SpecTypes.Object, + defaultValue: {type: 'first', name: 'Name'}, + properties: { + type: { + type: SpecTypes.String, + enum: ['first', 'second', 'third'], + viewSpec: { + type: 'select', + placeholder: 'Choose type', + layout: 'transparent', + layoutTitle: 'Type', + }, + }, + name: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + placeholder: 'Type your name', + layout: 'transparent', + layoutTitle: 'Name', + }, + }, + }, + viewSpec: { + type: 'inline', + layout: 'row', + layoutTitle: 'Candidate', + delimiter: {type: ':'}, + }, + }, +}; + export const VALUE: FormValue = { name: 'name', age: 10, }; + +export const VALUE_INLINE: FormValue = {type: 'first', name: 'Name'}; diff --git a/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx b/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx index 87c1d3ef..a38d37e9 100644 --- a/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx +++ b/src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx @@ -3,8 +3,7 @@ import React from 'react'; import _ from 'lodash'; import {Controller, FieldValue, ObjectIndependentInput, ValidateError} from '../../../../core'; - -const OBJECT_VALUE_PROPERTY_NAME = 'value'; +import {OBJECT_VALUE_PROPERTY_NAME} from '../../../constants/common'; export const ObjectValueInput: ObjectIndependentInput = (props) => { const {spec, input, name, Layout} = props; diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-chromium-linux.png new file mode 100644 index 00000000..e3e892b9 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-webkit-linux.png new file mode 100644 index 00000000..bc67da04 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-chromium-linux.png new file mode 100644 index 00000000..01541bff Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-webkit-linux.png new file mode 100644 index 00000000..2f6056b7 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-toggler-checkbox-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-chromium-linux.png new file mode 100644 index 00000000..423501a7 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-webkit-linux.png new file mode 100644 index 00000000..3dc79c57 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-chromium-linux.png new file mode 100644 index 00000000..7f70c7cb Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-webkit-linux.png new file mode 100644 index 00000000..98ab7307 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-Flat-view-toggler-checkbox-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-chromium-linux.png new file mode 100644 index 00000000..c41a3f2d Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-webkit-linux.png new file mode 100644 index 00000000..434742a1 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-chromium-linux.png new file mode 100644 index 00000000..7eb85e22 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-webkit-linux.png new file mode 100644 index 00000000..11516e9a Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-toggler-checkbox-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-chromium-linux.png new file mode 100644 index 00000000..e10c1bc1 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-webkit-linux.png new file mode 100644 index 00000000..cb211c03 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-dark-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-chromium-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-chromium-linux.png new file mode 100644 index 00000000..e8567968 Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-chromium-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-webkit-linux.png b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-webkit-linux.png new file mode 100644 index 00000000..41bdfd2e Binary files /dev/null and b/src/lib/kit/components/Inputs/OneOf/__snapshots__/OneOf.visual.test.tsx-snapshots/OneOf-view-toggler-checkbox-default-light-webkit-linux.png differ diff --git a/src/lib/kit/components/Inputs/OneOf/__tests__/OneOf.visual.test.tsx b/src/lib/kit/components/Inputs/OneOf/__tests__/OneOf.visual.test.tsx index cd09c1b2..3ae2ef59 100644 --- a/src/lib/kit/components/Inputs/OneOf/__tests__/OneOf.visual.test.tsx +++ b/src/lib/kit/components/Inputs/OneOf/__tests__/OneOf.visual.test.tsx @@ -50,6 +50,12 @@ test.describe('OneOf', () => { await expectScreenshot(); }); }); + + test('toggler checkbox default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); }); test.describe('OneOf view', () => { @@ -78,6 +84,12 @@ test.describe('OneOf view', () => { await expectScreenshot(); }); }); + + test('toggler checkbox default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); }); test.describe('OneOf Flat', () => { @@ -112,6 +124,12 @@ test.describe('OneOf Flat', () => { await expectScreenshot(); }); }); + + test('toggler checkbox default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); }); test.describe('OneOf Flat view', () => { @@ -140,4 +158,10 @@ test.describe('OneOf Flat view', () => { await expectScreenshot(); }); }); + + test('toggler checkbox default', async ({mount, expectScreenshot}) => { + await mount(); + + await expectScreenshot(); + }); }); diff --git a/src/lib/kit/components/Inputs/OneOf/__tests__/helpers.ts b/src/lib/kit/components/Inputs/OneOf/__tests__/helpers.ts index 6db521ba..4a489c7c 100644 --- a/src/lib/kit/components/Inputs/OneOf/__tests__/helpers.ts +++ b/src/lib/kit/components/Inputs/OneOf/__tests__/helpers.ts @@ -492,6 +492,73 @@ export const ONEOF: Record = { order: ['external', 'internal', 'empty'], }, }, + defaultCheckbox: { + type: SpecTypes.Object, + defaultValue: { + external: { + name: 'name', + age: 10, + }, + }, + properties: { + external: { + required: true, + type: SpecTypes.Object, + properties: { + name: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Name', + }, + }, + age: { + type: SpecTypes.Number, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Age', + }, + }, + license: { + type: SpecTypes.Boolean, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'License', + }, + }, + }, + viewSpec: { + type: 'base', + layoutTitle: 'Person data', + }, + }, + internal: { + required: true, + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Person id', + }, + }, + }, + viewSpec: { + type: 'oneof', + layout: 'row', + layoutTitle: 'Candidate', + order: ['external', 'internal'], + oneOfParams: { + toggler: 'checkbox', + booleanMap: { + true: 'external', + false: 'internal', + }, + }, + }, + }, }; export const VALUE: Record = { @@ -853,4 +920,68 @@ export const ONEOF_FALT: Record = { order: ['external', 'internal', 'empty'], }, }, + defaultCheckbox: { + type: SpecTypes.Object, + defaultValue: { + internal: 'string', + }, + properties: { + external: { + required: true, + type: SpecTypes.Object, + properties: { + name: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Name', + }, + }, + age: { + type: SpecTypes.Number, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Age', + }, + }, + license: { + type: SpecTypes.Boolean, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'License', + }, + }, + }, + viewSpec: { + type: 'base', + layoutTitle: 'Person data', + }, + }, + internal: { + required: true, + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'Person id', + }, + }, + }, + viewSpec: { + type: 'oneof_flat', + layout: 'row', + layoutTitle: 'Candidate', + order: ['external', 'internal'], + oneOfParams: { + toggler: 'checkbox', + booleanMap: { + true: 'external', + false: 'internal', + }, + }, + }, + }, }; diff --git a/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.scss b/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.scss index 3c13eecc..cd55ee8b 100644 --- a/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.scss +++ b/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.scss @@ -16,4 +16,11 @@ } } } + + &__delimiter { + display: flex; + margin-right: 8px; + align-items: center; + white-space: nowrap; + } } diff --git a/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.tsx b/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.tsx index 84b623df..ec9ec163 100644 --- a/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.tsx +++ b/src/lib/kit/components/Views/ObjectBaseView/ObjectBaseView.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import _ from 'lodash'; +import {Text} from '@gravity-ui/uikit'; +import isObjectLike from 'lodash/isObjectLike'; import {ObjectIndependentView, ObjectIndependentViewProps, ViewController} from '../../../../core'; import {block, filterPropertiesForObjectInline} from '../../../utils'; @@ -20,29 +21,38 @@ export const ObjectBaseView: React.FC = ({ Layout, ...restProps }) => { - if (!spec.properties || !_.isObjectLike(spec.properties)) { - return null; - } + const content = React.useMemo(() => { + if (!spec.properties || !isObjectLike(spec.properties)) { + return null; + } - const specProperties = inline - ? filterPropertiesForObjectInline(spec.properties) - : spec.properties; - - const content = ( -
- {(spec.viewSpec.order || Object.keys(specProperties)).map((property: string) => - specProperties[property] ? ( - - ) : null, - )} -
- ); + const specProperties = inline + ? filterPropertiesForObjectInline(spec.properties) + : spec.properties; + + const delimiter = spec.viewSpec.delimiter; + const orderProperties = spec.viewSpec.order || Object.keys(specProperties); + + return ( +
+ {orderProperties.map((property: string) => + specProperties[property] ? ( + + + {delimiter && delimiter[property] ? ( + {delimiter[property]} + ) : null} + + ) : null, + )} +
+ ); + }, [inline, name, spec.properties, spec.viewSpec.delimiter, spec.viewSpec.order]); - if (!Layout) { + if (!Layout || !content) { return content; } diff --git a/src/lib/kit/components/Views/ObjectValueInputView/ObjectValueInputView.tsx b/src/lib/kit/components/Views/ObjectValueInputView/ObjectValueInputView.tsx index c93ce372..f01fb33d 100644 --- a/src/lib/kit/components/Views/ObjectValueInputView/ObjectValueInputView.tsx +++ b/src/lib/kit/components/Views/ObjectValueInputView/ObjectValueInputView.tsx @@ -3,8 +3,7 @@ import React from 'react'; import _ from 'lodash'; import {ObjectIndependentView, ViewController} from '../../../../core'; - -const OBJECT_VALUE_PROPERTY_NAME = 'value'; +import {OBJECT_VALUE_PROPERTY_NAME} from '../../../constants/common'; export const ObjectValueInputView: ObjectIndependentView = ({spec, name, Layout, ...restProps}) => { const childSpec = React.useMemo(() => { diff --git a/src/lib/kit/components/Views/OneOfView/OneOfView.tsx b/src/lib/kit/components/Views/OneOfView/OneOfView.tsx index 4c06a365..fbba2e05 100644 --- a/src/lib/kit/components/Views/OneOfView/OneOfView.tsx +++ b/src/lib/kit/components/Views/OneOfView/OneOfView.tsx @@ -4,7 +4,7 @@ import _ from 'lodash'; import {GroupIndent} from '../../'; import {ObjectIndependentView, ObjectIndependentViewProps, ViewController} from '../../../../core'; -import {block} from '../../../utils'; +import {block, objectKeys} from '../../../utils'; import './OneOfView.scss'; @@ -22,15 +22,30 @@ const OneOfViewComponent: React.FC = (props) => { [spec.properties], ); + const specBooleanMap = React.useMemo( + () => spec.viewSpec.oneOfParams?.booleanMap, + [spec.viewSpec.oneOfParams?.booleanMap], + ); + const valueKey = React.useMemo(() => Object.keys(value)[0], [value]); const valueName = React.useMemo(() => { + if (spec.viewSpec.oneOfParams?.toggler === 'checkbox' && specBooleanMap) { + return objectKeys(specBooleanMap).find((key) => specBooleanMap[key] === valueKey); + } + return ( spec.description?.[valueKey] || specProperties[valueKey]?.viewSpec.layoutTitle || valueKey ); - }, [valueKey, spec.description, specProperties]); + }, [ + valueKey, + spec.description, + specProperties, + spec.viewSpec.oneOfParams?.toggler, + specBooleanMap, + ]); const wrappedValue = React.useMemo(() => { if (Layout) { diff --git a/src/lib/kit/constants/common.ts b/src/lib/kit/constants/common.ts index be8db571..acfcff4d 100644 --- a/src/lib/kit/constants/common.ts +++ b/src/lib/kit/constants/common.ts @@ -3,3 +3,5 @@ import type {PopoverProps} from '@gravity-ui/uikit'; export const COMMON_POPOVER_PLACEMENT: PopoverProps['placement'] = ['bottom', 'top']; export const COMMON_TITLE_MAX_WIDTH = 533; + +export const OBJECT_VALUE_PROPERTY_NAME = 'value'; diff --git a/src/lib/kit/hooks/useOneOf/useOneOf.scss b/src/lib/kit/hooks/useOneOf/useOneOf.scss index 3571bc9a..d8a18789 100644 --- a/src/lib/kit/hooks/useOneOf/useOneOf.scss +++ b/src/lib/kit/hooks/useOneOf/useOneOf.scss @@ -26,4 +26,10 @@ margin-right: 8px; } } + + &__checkbox { + height: 28px; + display: flex; + align-items: center; + } } diff --git a/src/lib/kit/hooks/useOneOf/useOneOf.tsx b/src/lib/kit/hooks/useOneOf/useOneOf.tsx index 2880436a..22c2933f 100644 --- a/src/lib/kit/hooks/useOneOf/useOneOf.tsx +++ b/src/lib/kit/hooks/useOneOf/useOneOf.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import {RadioButton, Select} from '@gravity-ui/uikit'; -import _ from 'lodash'; +import {Checkbox, RadioButton, Select} from '@gravity-ui/uikit'; +import isObjectLike from 'lodash/isObjectLike'; +import some from 'lodash/some'; import {ObjectIndependentInputProps} from '../../../core'; import {TogglerCard} from '../../components'; -import {block} from '../../utils'; +import {block, objectKeys} from '../../utils'; import './useOneOf.scss'; @@ -22,14 +23,19 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => { const {name, input, spec, Layout} = props; const specProperties = React.useMemo( - () => (_.isObjectLike(spec.properties) ? spec.properties! : {}), + () => (isObjectLike(spec.properties) ? spec.properties! : {}), [spec.properties], ); + const specBooleanMap = React.useMemo( + () => spec.viewSpec.oneOfParams?.booleanMap, + [spec.viewSpec.oneOfParams?.booleanMap], + ); + const [oneOfValue, setOneOfValue] = React.useState(() => { let valueKeys: string[] | undefined; - if (_.isObjectLike(input.value)) { + if (isObjectLike(input.value)) { const keys = Object.keys(input.value); if (keys.length) { @@ -51,6 +57,30 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => { [setOneOfValue, input.onChange, oneOfValue], ); + const onCheckboxChange = React.useCallback( + (checked: boolean) => { + if (specBooleanMap) { + const value = String(checked) as 'true' | 'false'; + const newValue = specBooleanMap[value]; + + onOneOfChange([newValue]); + } + }, + [onOneOfChange, specBooleanMap], + ); + + const checkboxValue = React.useMemo(() => { + if (specBooleanMap) { + const keyBooleanMap = objectKeys(specBooleanMap).find( + (key) => specBooleanMap[key] === oneOfValue, + ); + + return keyBooleanMap === 'true'; + } + + return undefined; + }, [oneOfValue, specBooleanMap]); + const options = React.useMemo( () => (spec.viewSpec.order || Object.keys(specProperties)).map((value) => { @@ -78,13 +108,21 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => { spec.viewSpec.oneOfParams?.toggler !== 'radio' && (spec.viewSpec.oneOfParams?.toggler === 'select' || options.length > 3 || - _.some(options, ({title}) => title.length > MAX_TAB_TITLE_LENGTH)) + some(options, ({title}) => title.length > MAX_TAB_TITLE_LENGTH)) ) { return 'select'; } + if ( + spec.viewSpec.oneOfParams?.toggler === 'checkbox' && + options.length === 2 && + specBooleanMap + ) { + return 'checkbox'; + } + return 'radio'; - }, [options, spec.viewSpec.oneOfParams?.toggler]); + }, [options, spec.viewSpec.oneOfParams?.toggler, specBooleanMap]); const togglerInput = React.useMemo(() => { if (togglerType === 'card') { @@ -125,6 +163,19 @@ export const useOneOf = ({props, onTogglerChange}: UseOneOfParams) => { ); } + if (togglerType === 'checkbox') { + return ( +
+ +
+ ); + } + return ( { togglerType, oneOfValue, spec.viewSpec.disabled, + spec.description, name, options, onOneOfChange, specProperties, + onCheckboxChange, + checkboxValue, ]); const toggler = React.useMemo(() => { diff --git a/src/lib/kit/utils/index.ts b/src/lib/kit/utils/index.ts index cc72e81d..7d22dc3a 100644 --- a/src/lib/kit/utils/index.ts +++ b/src/lib/kit/utils/index.ts @@ -2,3 +2,4 @@ export * from './cn'; export * from './common'; export * from './bigIntMath'; export * from './objectInline'; +export * from './objectKeys'; diff --git a/src/lib/kit/utils/objectKeys.ts b/src/lib/kit/utils/objectKeys.ts new file mode 100644 index 00000000..b5bcbdb3 --- /dev/null +++ b/src/lib/kit/utils/objectKeys.ts @@ -0,0 +1,7 @@ +type Dictionary = Record; + +type KeysOf = T extends Dictionary ? `${Exclude}` : never; + +export function objectKeys>(obj: T) { + return Object.keys(obj) as Array>; +} diff --git a/src/stories/ObjectBase.stories.tsx b/src/stories/ObjectBase.stories.tsx index a4c97799..e8db0bc9 100644 --- a/src/stories/ObjectBase.stories.tsx +++ b/src/stories/ObjectBase.stories.tsx @@ -37,7 +37,12 @@ const baseSpec: ObjectSpec = { const value = {name: 'Foo', age: 13, license: false}; -const excludeOptions = ['description', 'viewSpec.type', 'viewSpec.oneOfParams']; +const excludeOptions = [ + 'description', + 'viewSpec.type', + 'viewSpec.oneOfParams', + 'viewSpec.delimiter', +]; const template = (spec: ObjectSpec = baseSpec) => { const Template: StoryFn = (__, {viewMode}) => ( diff --git a/src/stories/ObjectCardOneOf.stories.tsx b/src/stories/ObjectCardOneOf.stories.tsx index 86378beb..248b3659 100644 --- a/src/stories/ObjectCardOneOf.stories.tsx +++ b/src/stories/ObjectCardOneOf.stories.tsx @@ -59,7 +59,7 @@ const baseSpec: ObjectSpec = { }, }; -const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder']; +const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder', 'viewSpec.delimiter']; const template = (spec: ObjectSpec = baseSpec) => { const Template: StoryFn = (__, {viewMode}) => ( diff --git a/src/stories/ObjectInline.stories.tsx b/src/stories/ObjectInline.stories.tsx index 51d3c445..667a79e3 100644 --- a/src/stories/ObjectInline.stories.tsx +++ b/src/stories/ObjectInline.stories.tsx @@ -45,6 +45,10 @@ const baseSpec: ObjectSpec = { type: 'inline', layout: 'row', layoutTitle: 'Candidate', + delimiter: { + type: ':', + name: '-', + }, }, }; diff --git a/src/stories/ObjectMultiOneOf.stories.tsx b/src/stories/ObjectMultiOneOf.stories.tsx index c6a37ec7..60cd889d 100644 --- a/src/stories/ObjectMultiOneOf.stories.tsx +++ b/src/stories/ObjectMultiOneOf.stories.tsx @@ -61,6 +61,7 @@ const excludeOptions = [ 'viewSpec.itemLabel', 'viewSpec.table', 'viewSpec.oneOfParams', + 'viewSpec.delimiter', ]; const value = { diff --git a/src/stories/ObjectMultiOneOfFlat.stories.tsx b/src/stories/ObjectMultiOneOfFlat.stories.tsx index 69575cb2..3c18390b 100644 --- a/src/stories/ObjectMultiOneOfFlat.stories.tsx +++ b/src/stories/ObjectMultiOneOfFlat.stories.tsx @@ -61,6 +61,7 @@ const excludeOptions = [ 'viewSpec.itemLabel', 'viewSpec.table', 'viewSpec.oneOfParams', + 'viewSpec.delimiter', ]; const value = { diff --git a/src/stories/ObjectOneOf.stories.tsx b/src/stories/ObjectOneOf.stories.tsx index 9b2bb5b7..48647065 100644 --- a/src/stories/ObjectOneOf.stories.tsx +++ b/src/stories/ObjectOneOf.stories.tsx @@ -60,7 +60,7 @@ const baseSpec: ObjectSpec = { }, }; -const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder']; +const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder', 'viewSpec.delimiter']; const template = (spec: ObjectSpec = baseSpec) => { const Template: StoryFn = (__, {viewMode}) => ( @@ -71,3 +71,47 @@ const template = (spec: ObjectSpec = baseSpec) => { }; export const OneOf = template(); + +export const OneOfCheckbox = template({ + ...baseSpec, + properties: { + internal: { + required: true, + type: SpecTypes.String, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Person id'}, + }, + external: { + required: true, + type: SpecTypes.Object, + properties: { + name: { + type: SpecTypes.String, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Name'}, + }, + age: { + type: SpecTypes.Number, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Age'}, + }, + license: { + type: SpecTypes.Boolean, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'License'}, + }, + }, + viewSpec: { + type: 'base', + layoutTitle: 'Person data', + }, + }, + }, + viewSpec: { + ...baseSpec.viewSpec, + order: ['external', 'internal'], + oneOfParams: { + toggler: 'checkbox', + booleanMap: { + true: 'external', + false: 'internal', + }, + }, + }, +}); diff --git a/src/stories/ObjectOneOfFlat.stories.tsx b/src/stories/ObjectOneOfFlat.stories.tsx index 13c32411..1907950d 100644 --- a/src/stories/ObjectOneOfFlat.stories.tsx +++ b/src/stories/ObjectOneOfFlat.stories.tsx @@ -60,7 +60,7 @@ const baseSpec: ObjectSpec = { }, }; -const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder']; +const excludeOptions = ['viewSpec.type', 'viewSpec.placeholder', 'viewSpec.delimiter']; const template = (spec: ObjectSpec = baseSpec) => { const Template: StoryFn = (__, {viewMode}) => ( @@ -71,3 +71,47 @@ const template = (spec: ObjectSpec = baseSpec) => { }; export const OneOfFlat = template(); + +export const OneOfFlatCheckbox = template({ + ...baseSpec, + properties: { + empty: { + required: true, + type: SpecTypes.Object, + viewSpec: {type: 'base', layoutTitle: 'Empty'}, + }, + external: { + required: true, + type: SpecTypes.Object, + properties: { + name: { + type: SpecTypes.String, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Name'}, + }, + age: { + type: SpecTypes.Number, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Age'}, + }, + license: { + type: SpecTypes.Boolean, + viewSpec: {type: 'base', layout: 'row', layoutTitle: 'License'}, + }, + }, + viewSpec: { + type: 'base', + layoutTitle: 'Person data', + }, + }, + }, + viewSpec: { + ...baseSpec.viewSpec, + order: ['empty', 'external'], + oneOfParams: { + toggler: 'checkbox', + booleanMap: { + true: 'external', + false: 'empty', + }, + }, + }, +}); diff --git a/src/stories/ObjectSecret.stories.tsx b/src/stories/ObjectSecret.stories.tsx index 644b61d1..2337b619 100644 --- a/src/stories/ObjectSecret.stories.tsx +++ b/src/stories/ObjectSecret.stories.tsx @@ -35,6 +35,7 @@ const excludeOptions = [ 'viewSpec.disabled', 'viewSpec.oneOfParams', 'viewSpec.placeholder', + 'viewSpec.delimiter', ]; const template = (spec: ObjectSpec = baseSpec) => { diff --git a/src/stories/ObjectTextLink.stories.tsx b/src/stories/ObjectTextLink.stories.tsx index 1248f6ff..8f78f090 100644 --- a/src/stories/ObjectTextLink.stories.tsx +++ b/src/stories/ObjectTextLink.stories.tsx @@ -40,6 +40,7 @@ const excludeOptions = [ 'viewSpec.disabled', 'viewSpec.oneOfParams', 'viewSpec.placeholder', + 'viewSpec.delimiter', ]; const template = (spec: ObjectSpec = baseSpec) => { diff --git a/src/stories/ObjectValue.stories.tsx b/src/stories/ObjectValue.stories.tsx index 6133cb9d..ec071064 100644 --- a/src/stories/ObjectValue.stories.tsx +++ b/src/stories/ObjectValue.stories.tsx @@ -37,6 +37,7 @@ const excludeOptions = [ 'viewSpec.disabled', 'viewSpec.oneOfParams', 'viewSpec.placeholder', + 'viewSpec.delimiter', ]; const template = (spec: ObjectSpec = baseSpec) => { diff --git a/src/stories/components/InputPreview/constants.ts b/src/stories/components/InputPreview/constants.ts index c90f70b8..7f86190f 100644 --- a/src/stories/components/InputPreview/constants.ts +++ b/src/stories/components/InputPreview/constants.ts @@ -221,6 +221,33 @@ const itemPrefix: StringSpec = { viewSpec: {type: 'base', layout: 'row', layoutTitle: 'Item Prefix'}, }; +const delimiter: ArraySpec = { + type: SpecTypes.Array, + items: { + type: SpecTypes.Object, + properties: { + property: { + type: SpecTypes.String, + viewSpec: {type: 'base', layout: 'table_item'}, + }, + delimiter: { + type: SpecTypes.String, + viewSpec: {type: 'base', layout: 'table_item'}, + }, + }, + viewSpec: {type: ''}, + }, + viewSpec: { + type: 'table', + layout: 'accordeon', + layoutTitle: 'Delimiter', + table: [ + {label: 'Property', property: 'property'}, + {label: 'Delimiter', property: 'delimiter'}, + ], + }, +}; + const addButtonPosition: StringSpec = { type: SpecTypes.String, enum: ['―', 'down', 'right'], @@ -363,9 +390,36 @@ const oneOfParams: ObjectSpec = { properties: { toggler: { type: SpecTypes.String, - enum: ['―', 'radio', 'select', 'card'], + enum: ['―', 'radio', 'select', 'card', 'checkbox'], viewSpec: {type: 'select', layout: 'row', layoutTitle: 'Switch type'}, }, + booleanMap: { + type: SpecTypes.Object, + properties: { + true: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'True property', + }, + }, + false: { + type: SpecTypes.String, + viewSpec: { + type: 'base', + layout: 'row', + layoutTitle: 'False property', + }, + }, + }, + viewSpec: { + type: 'base', + layout: 'accordeon', + layoutTitle: 'Boolean Map', + layoutOpen: true, + }, + }, }, viewSpec: { type: 'base', @@ -581,6 +635,7 @@ export const getObjectOptions = (): ObjectSpec => ({ oneOfParams, placeholder, hidden, + delimiter, }, [ 'disabled', @@ -593,6 +648,7 @@ export const getObjectOptions = (): ObjectSpec => ({ 'oneOfParams', 'placeholder', 'hidden', + 'delimiter', ], ), }, diff --git a/src/stories/components/InputPreview/utils.ts b/src/stories/components/InputPreview/utils.ts index 88a48370..9dc79a98 100644 --- a/src/stories/components/InputPreview/utils.ts +++ b/src/stories/components/InputPreview/utils.ts @@ -67,6 +67,15 @@ export const transformCorrect = (spec: Spec) => { })) as unknown as Record; } + if (isObjectSpec(_spec) && _spec.viewSpec.delimiter) { + const correctDelimiter = _spec.viewSpec.delimiter; + + _spec.viewSpec.delimiter = Object.keys(correctDelimiter).map((key) => ({ + property: key, + delimiter: correctDelimiter[key], + })) as unknown as Record; + } + return _spec; }; @@ -155,6 +164,22 @@ export const transformIncorrect = (spec: Spec) => { ); } + if (isObjectSpec(_spec) && _spec.viewSpec.delimiter) { + const incorrectDelimiter = _spec.viewSpec.delimiter as unknown as { + property: string; + delimiter: string; + }[]; + + _spec.viewSpec.delimiter = incorrectDelimiter.reduce( + (acc: Record, {property, delimiter}) => { + acc[property] = delimiter; + + return acc; + }, + {}, + ); + } + return _spec; };