Skip to content

Commit b859136

Browse files
authored
feat(BooleanOneOf): add new input BooleanOneOf (#182)
1 parent 5012d5d commit b859136

31 files changed

+368
-14
lines changed

docs/spec.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,10 @@ type Spec = ArraySpec | BooleanSpec | NumberSpec | ObjectSpec | StringSpec;
145145

146146
#### OneOfParams
147147

148-
| Property | Type | Required | Description |
149-
| :------- | :---------------------------- | :------: | :---------- |
150-
| toggler | `'select'` `'radio'` `'card'` | | Switch type |
148+
| Property | Type | Required | Description |
149+
| :--------- | :----------------------------------------- | :------: | :--------------------------------------------- |
150+
| toggler | `'select'` `'radio'` `'card'` `'checkbox'` | | Switch type |
151+
| booleanMap | `Record<'true' 'false', string>` | | Special object for oneof toggler type checkbox |
151152

152153
#### FileInput
153154

src/lib/core/types/specs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ export interface ObjectSpec<
117117
order?: string[];
118118
link?: LinkType;
119119
oneOfParams?: {
120-
toggler?: 'select' | 'radio' | 'card';
120+
toggler?: 'select' | 'radio' | 'card' | 'checkbox';
121+
booleanMap?: Record<'true' | 'false', string>;
121122
};
122123
placeholder?: string;
123124
hidden?: boolean;

src/lib/kit/components/Inputs/ObjectValueInput/ObjectValueInput.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import cloneDeep from 'lodash/cloneDeep';
44
import set from 'lodash/set';
55

66
import {Controller, FieldValue, ObjectIndependentInput, ValidateError} from '../../../../core';
7-
8-
const OBJECT_VALUE_PROPERTY_NAME = 'value';
7+
import {OBJECT_VALUE_PROPERTY_NAME} from '../../../constants/common';
98

109
export const ObjectValueInput: ObjectIndependentInput = (props) => {
1110
const {spec, input, name, Layout} = props;

src/lib/kit/components/Inputs/OneOf/__tests__/OneOf.visual.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ test.describe('OneOf', () => {
5050
await expectScreenshot();
5151
});
5252
});
53+
54+
test('toggler checkbox default', async ({mount, expectScreenshot}) => {
55+
await mount(<DynamicForm spec={ONEOF.defaultCheckbox} />);
56+
57+
await expectScreenshot();
58+
});
5359
});
5460

5561
test.describe('OneOf view', () => {
@@ -78,6 +84,12 @@ test.describe('OneOf view', () => {
7884
await expectScreenshot();
7985
});
8086
});
87+
88+
test('toggler checkbox default', async ({mount, expectScreenshot}) => {
89+
await mount(<DynamicView spec={ONEOF.defaultCheckbox} value={VALUE.object} />);
90+
91+
await expectScreenshot();
92+
});
8193
});
8294

8395
test.describe('OneOf Flat', () => {
@@ -112,6 +124,12 @@ test.describe('OneOf Flat', () => {
112124
await expectScreenshot();
113125
});
114126
});
127+
128+
test('toggler checkbox default', async ({mount, expectScreenshot}) => {
129+
await mount(<DynamicForm spec={ONEOF_FALT.defaultCheckbox} />);
130+
131+
await expectScreenshot();
132+
});
115133
});
116134

117135
test.describe('OneOf Flat view', () => {
@@ -140,4 +158,10 @@ test.describe('OneOf Flat view', () => {
140158
await expectScreenshot();
141159
});
142160
});
161+
162+
test('toggler checkbox default', async ({mount, expectScreenshot}) => {
163+
await mount(<DynamicView spec={ONEOF_FALT.defaultCheckbox} value={VALUE.string} />);
164+
165+
await expectScreenshot();
166+
});
143167
});

src/lib/kit/components/Inputs/OneOf/__tests__/helpers.ts

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,73 @@ export const ONEOF: Record<string, ObjectSpec> = {
492492
order: ['external', 'internal', 'empty'],
493493
},
494494
},
495+
defaultCheckbox: {
496+
type: SpecTypes.Object,
497+
defaultValue: {
498+
external: {
499+
name: 'name',
500+
age: 10,
501+
},
502+
},
503+
properties: {
504+
external: {
505+
required: true,
506+
type: SpecTypes.Object,
507+
properties: {
508+
name: {
509+
type: SpecTypes.String,
510+
viewSpec: {
511+
type: 'base',
512+
layout: 'row',
513+
layoutTitle: 'Name',
514+
},
515+
},
516+
age: {
517+
type: SpecTypes.Number,
518+
viewSpec: {
519+
type: 'base',
520+
layout: 'row',
521+
layoutTitle: 'Age',
522+
},
523+
},
524+
license: {
525+
type: SpecTypes.Boolean,
526+
viewSpec: {
527+
type: 'base',
528+
layout: 'row',
529+
layoutTitle: 'License',
530+
},
531+
},
532+
},
533+
viewSpec: {
534+
type: 'base',
535+
layoutTitle: 'Person data',
536+
},
537+
},
538+
internal: {
539+
required: true,
540+
type: SpecTypes.String,
541+
viewSpec: {
542+
type: 'base',
543+
layout: 'row',
544+
layoutTitle: 'Person id',
545+
},
546+
},
547+
},
548+
viewSpec: {
549+
type: 'oneof',
550+
layout: 'row',
551+
layoutTitle: 'Candidate',
552+
order: ['external', 'internal'],
553+
oneOfParams: {
554+
toggler: 'checkbox',
555+
booleanMap: {
556+
true: 'external',
557+
false: 'internal',
558+
},
559+
},
560+
},
561+
},
495562
};
496563

497564
export const VALUE: Record<string, FormValue> = {
@@ -853,4 +920,68 @@ export const ONEOF_FALT: Record<string, ObjectSpec> = {
853920
order: ['external', 'internal', 'empty'],
854921
},
855922
},
923+
defaultCheckbox: {
924+
type: SpecTypes.Object,
925+
defaultValue: {
926+
internal: 'string',
927+
},
928+
properties: {
929+
external: {
930+
required: true,
931+
type: SpecTypes.Object,
932+
properties: {
933+
name: {
934+
type: SpecTypes.String,
935+
viewSpec: {
936+
type: 'base',
937+
layout: 'row',
938+
layoutTitle: 'Name',
939+
},
940+
},
941+
age: {
942+
type: SpecTypes.Number,
943+
viewSpec: {
944+
type: 'base',
945+
layout: 'row',
946+
layoutTitle: 'Age',
947+
},
948+
},
949+
license: {
950+
type: SpecTypes.Boolean,
951+
viewSpec: {
952+
type: 'base',
953+
layout: 'row',
954+
layoutTitle: 'License',
955+
},
956+
},
957+
},
958+
viewSpec: {
959+
type: 'base',
960+
layoutTitle: 'Person data',
961+
},
962+
},
963+
internal: {
964+
required: true,
965+
type: SpecTypes.String,
966+
viewSpec: {
967+
type: 'base',
968+
layout: 'row',
969+
layoutTitle: 'Person id',
970+
},
971+
},
972+
},
973+
viewSpec: {
974+
type: 'oneof_flat',
975+
layout: 'row',
976+
layoutTitle: 'Candidate',
977+
order: ['external', 'internal'],
978+
oneOfParams: {
979+
toggler: 'checkbox',
980+
booleanMap: {
981+
true: 'external',
982+
false: 'internal',
983+
},
984+
},
985+
},
986+
},
856987
};

src/lib/kit/components/Views/ObjectValueInputView/ObjectValueInputView.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import React from 'react';
33
import cloneDeep from 'lodash/cloneDeep';
44

55
import {ObjectIndependentView, ViewController} from '../../../../core';
6-
7-
const OBJECT_VALUE_PROPERTY_NAME = 'value';
6+
import {OBJECT_VALUE_PROPERTY_NAME} from '../../../constants/common';
87

98
export const ObjectValueInputView: ObjectIndependentView = ({spec, name, Layout, ...restProps}) => {
109
const childSpec = React.useMemo(() => {

src/lib/kit/components/Views/OneOfView/OneOfView.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import isObjectLike from 'lodash/isObjectLike';
44

55
import {GroupIndent} from '../../';
66
import {ObjectIndependentView, ObjectIndependentViewProps, ViewController} from '../../../../core';
7-
import {block} from '../../../utils';
7+
import {block, objectKeys} from '../../../utils';
88

99
import './OneOfView.scss';
1010

@@ -22,15 +22,30 @@ const OneOfViewComponent: React.FC<OneOfViewProps> = (props) => {
2222
[spec.properties],
2323
);
2424

25+
const specBooleanMap = React.useMemo(
26+
() => spec.viewSpec.oneOfParams?.booleanMap,
27+
[spec.viewSpec.oneOfParams?.booleanMap],
28+
);
29+
2530
const valueKey = React.useMemo(() => Object.keys(value)[0], [value]);
2631

2732
const valueName = React.useMemo(() => {
33+
if (spec.viewSpec.oneOfParams?.toggler === 'checkbox' && specBooleanMap) {
34+
return objectKeys(specBooleanMap).find((key) => specBooleanMap[key] === valueKey);
35+
}
36+
2837
return (
2938
spec.description?.[valueKey] ||
3039
specProperties[valueKey]?.viewSpec.layoutTitle ||
3140
valueKey
3241
);
33-
}, [valueKey, spec.description, specProperties]);
42+
}, [
43+
valueKey,
44+
spec.description,
45+
specProperties,
46+
spec.viewSpec.oneOfParams?.toggler,
47+
specBooleanMap,
48+
]);
3449

3550
const wrappedValue = React.useMemo(() => {
3651
if (Layout) {

src/lib/kit/constants/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ import type {PopoverProps} from '@gravity-ui/uikit';
33
export const COMMON_POPOVER_PLACEMENT: PopoverProps['placement'] = ['bottom', 'top'];
44

55
export const COMMON_TITLE_MAX_WIDTH = 533;
6+
7+
export const OBJECT_VALUE_PROPERTY_NAME = 'value';

src/lib/kit/hooks/useOneOf/useOneOf.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@
2626
margin-right: 8px;
2727
}
2828
}
29+
30+
&__checkbox {
31+
height: 28px;
32+
display: flex;
33+
align-items: center;
34+
}
2935
}

0 commit comments

Comments
 (0)