Skip to content

Commit 0138f29

Browse files
authored
feat: add column view (#257)
1 parent e7a710c commit 0138f29

25 files changed

+405
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
@import '../../../styles/variables.scss';
2+
3+
.#{$ns}column {
4+
margin-bottom: 15px;
5+
6+
&:last-child {
7+
margin-bottom: 0;
8+
}
9+
10+
&__first-row {
11+
min-height: 28px;
12+
display: flex;
13+
margin-bottom: auto;
14+
flex-direction: column;
15+
flex-shrink: 0;
16+
17+
&-inner {
18+
display: inline;
19+
margin-top: auto;
20+
margin-bottom: auto;
21+
}
22+
23+
&::after {
24+
content: '';
25+
width: 100%;
26+
flex-shrink: 1;
27+
}
28+
}
29+
30+
&__title {
31+
word-break: break-word;
32+
margin-right: 3px;
33+
34+
&_required {
35+
&::after {
36+
content: '*';
37+
color: var(--g-color-text-danger);
38+
}
39+
}
40+
}
41+
42+
&__note {
43+
position: relative;
44+
45+
&-inner {
46+
position: absolute;
47+
margin-top: 1px;
48+
49+
.g-help-popover {
50+
display: flex;
51+
52+
& > span {
53+
display: flex;
54+
}
55+
}
56+
}
57+
}
58+
59+
&__second-row {
60+
display: flex;
61+
flex-direction: column;
62+
flex-grow: 1;
63+
64+
&-inner {
65+
display: flex;
66+
justify-content: space-around;
67+
}
68+
}
69+
70+
&__remove-button {
71+
margin-left: 5px;
72+
}
73+
74+
&__required-mark {
75+
color: var(--g-color-text-danger);
76+
}
77+
78+
&__error-wrapper {
79+
min-width: 100%;
80+
}
81+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React from 'react';
2+
3+
import {HelpPopover} from '@gravity-ui/components';
4+
import {TrashBin} from '@gravity-ui/icons';
5+
import {Button, Icon, Text} from '@gravity-ui/uikit';
6+
7+
import {
8+
FieldValue,
9+
LayoutProps,
10+
Spec,
11+
StringSpec,
12+
isArrayItem,
13+
isArraySpec,
14+
isObjectSpec,
15+
withGenerateButton,
16+
} from '../../../../core';
17+
import {ErrorWrapper, GenerateRandomValueButton} from '../../../components';
18+
import {block} from '../../../utils';
19+
20+
import './Column.scss';
21+
22+
const b = block('column');
23+
24+
interface ColumnProps {}
25+
26+
const ColumnBase = <T extends FieldValue, S extends Spec>({
27+
name,
28+
spec,
29+
input,
30+
meta,
31+
children,
32+
}: LayoutProps<T, undefined, undefined, S> & ColumnProps) => {
33+
const arrayItem = React.useMemo(() => isArrayItem(name), [name]);
34+
const generateButton = React.useMemo(() => withGenerateButton(spec), [spec]);
35+
36+
return (
37+
<div className={b()}>
38+
<div className={b('first-row')}>
39+
<div className={b('first-row-inner')}>
40+
<Text className={b('title', {required: spec.required})}>
41+
{spec.viewSpec.layoutTitle}
42+
</Text>
43+
{spec.viewSpec.layoutDescription ? (
44+
<span className={b('note')}>
45+
<Text className={b('note-inner')}>
46+
<HelpPopover
47+
htmlContent={spec.viewSpec.layoutDescription}
48+
placement={['bottom', 'top']}
49+
/>
50+
</Text>
51+
</span>
52+
) : null}
53+
</div>
54+
</div>
55+
<div className={b('second-row')}>
56+
<div className={b('second-row-inner')}>
57+
<ErrorWrapper
58+
name={name}
59+
meta={meta}
60+
withoutChildErrorStyles={
61+
// TODO: remove condition spec.viewSpec.type !== 'select'
62+
(isArraySpec(spec) && spec.viewSpec.type !== 'select') ||
63+
isObjectSpec(spec)
64+
}
65+
className={b('error-wrapper')}
66+
>
67+
{children}
68+
</ErrorWrapper>
69+
{generateButton ? (
70+
<GenerateRandomValueButton
71+
spec={spec as StringSpec}
72+
onChange={input.onChange as (value: string) => void}
73+
/>
74+
) : null}
75+
{arrayItem ? (
76+
<Button
77+
view="flat-secondary"
78+
className={b('remove-button')}
79+
onClick={input.onDrop}
80+
qa={`${name}-remove-item`}
81+
>
82+
<Icon data={TrashBin} size={16} />
83+
</Button>
84+
) : null}
85+
</div>
86+
</div>
87+
</div>
88+
);
89+
};
90+
91+
export const Column = <T extends FieldValue, S extends Spec>(
92+
props: LayoutProps<T, undefined, undefined, S>,
93+
) => <ColumnBase {...props} />;
Loading
18.6 KB
Loading
Loading
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
3+
import {COLUMN_CARD} from './helpers';
4+
5+
import {test} from '~playwright/core';
6+
import {DynamicForm} from '~playwright/core/DynamicForm';
7+
8+
test.describe('Column Form', () => {
9+
test('object spec', async ({mount, expectScreenshot}) => {
10+
await mount(<DynamicForm spec={COLUMN_CARD} />);
11+
12+
await expectScreenshot();
13+
});
14+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {FormValue, ObjectSpec, SpecTypes} from '../../../../../core';
2+
3+
export const COLUMN_CARD: ObjectSpec = {
4+
defaultValue: {
5+
name: 'value',
6+
age: 10,
7+
license: false,
8+
},
9+
type: SpecTypes.Object,
10+
properties: {
11+
name: {
12+
type: SpecTypes.String,
13+
viewSpec: {
14+
type: 'base',
15+
layout: 'column',
16+
layoutDescription: 'Description for Name',
17+
layoutTitle: 'Name',
18+
},
19+
},
20+
age: {
21+
type: SpecTypes.Number,
22+
viewSpec: {
23+
type: 'base',
24+
layout: 'column',
25+
layoutDescription: 'Description for Age',
26+
layoutTitle: 'Age',
27+
},
28+
},
29+
license: {
30+
type: SpecTypes.Boolean,
31+
viewSpec: {
32+
type: 'base',
33+
layout: 'column',
34+
layoutDescription: 'Description for License',
35+
layoutTitle: 'License',
36+
},
37+
},
38+
},
39+
viewSpec: {
40+
type: 'base',
41+
layout: 'accordeon',
42+
layoutTitle: 'Candidate',
43+
layoutDescription: 'Description for base',
44+
layoutOpen: true,
45+
},
46+
};
47+
48+
export const VALUE: Record<string, FormValue> = {
49+
array: ['value', 'value'],
50+
object: {
51+
name: 'name',
52+
age: 21,
53+
license: true,
54+
},
55+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Column';

src/lib/kit/components/Layouts/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from './AccordeonCard';
33
export * from './CardAccordeon';
44
export * from './CardSection';
55
export * from './Row';
6+
export * from './Column';
67
export * from './Section';
78
export * from './TableCell';
89
export * from './Transparent';

0 commit comments

Comments
 (0)