Skip to content

Commit dae7262

Browse files
authored
feat(Flex): New component (#7052)
* feat(Flex): New component * fix: Unified type * test: Add unit test and update snapshots * docs: update md file --------- Co-authored-by: undefined <undefined>
1 parent 8cf6be1 commit dae7262

20 files changed

+803
-0
lines changed

Diff for: components/_util/gapSize.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { SizeType } from '../config-provider/SizeContext';
2+
3+
export function isPresetSize(size?: SizeType | string | number): size is SizeType {
4+
return ['small', 'middle', 'large'].includes(size as string);
5+
}
6+
7+
export function isValidGapNumber(size?: SizeType | string | number): size is number {
8+
if (!size) {
9+
// The case of size = 0 is deliberately excluded here, because the default value of the gap attribute in CSS is 0, so if the user passes 0 in, we can directly ignore it.
10+
return false;
11+
}
12+
return typeof size === 'number' && !Number.isNaN(size);
13+
}

Diff for: components/_util/type.ts

+2
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,5 @@ export function someType<T>(types?: any[], defaultVal?: T) {
9292
}
9393

9494
export type CustomSlotsType<T> = SlotsType<T>;
95+
96+
export type AnyObject = Record<PropertyKey, any>;

Diff for: components/components.ts

+3
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,6 @@ export { default as Tour } from './tour';
264264

265265
export type { AppProps } from './app';
266266
export { default as App } from './app';
267+
268+
export type { FlexProps } from './flex';
269+
export { default as Flex } from './flex';

Diff for: components/config-provider/context.ts

+3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ export interface ConfigProviderInnerProps {
151151
wave?: ComputedRef<{
152152
disabled?: boolean;
153153
}>;
154+
flex?: ComputedRef<{
155+
vertical?: boolean;
156+
}>;
154157
}
155158

156159
export const configProviderKey: InjectionKey<ConfigProviderInnerProps> = Symbol('configProvider');
+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders ./components/flex/demo/align.vue correctly 1`] = `
4+
<div class="ant-flex ant-flex-align-start ant-flex-gap-middle ant-flex-vertical">
5+
<p>Select justify :</p>
6+
<div class="ant-segmented ">
7+
<div class="ant-segmented-group">
8+
<!----><label class="ant-segmented-item ant-segmented-item-selected"><input class="ant-segmented-item-input" type="radio">
9+
<div class="ant-segmented-item-label" title="flex-start">flex-start</div>
10+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
11+
<div class="ant-segmented-item-label" title="center">center</div>
12+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
13+
<div class="ant-segmented-item-label" title="flex-end">flex-end</div>
14+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
15+
<div class="ant-segmented-item-label" title="space-between">space-between</div>
16+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
17+
<div class="ant-segmented-item-label" title="space-around">space-around</div>
18+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
19+
<div class="ant-segmented-item-label" title="space-evenly">space-evenly</div>
20+
</label>
21+
</div>
22+
</div>
23+
<p>Select align :</p>
24+
<div class="ant-segmented ">
25+
<div class="ant-segmented-group">
26+
<!----><label class="ant-segmented-item ant-segmented-item-selected"><input class="ant-segmented-item-input" type="radio">
27+
<div class="ant-segmented-item-label" title="flex-start">flex-start</div>
28+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
29+
<div class="ant-segmented-item-label" title="center">center</div>
30+
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
31+
<div class="ant-segmented-item-label" title="flex-end">flex-end</div>
32+
</label>
33+
</div>
34+
</div>
35+
<div class="ant-flex ant-flex-align-flex-start ant-flex-justify-flex-start" style="width: 100%; height: 120px; border-radius: 6px; border: 1px solid #40a9ff;"><button class="ant-btn ant-btn-primary" type="button">
36+
<!----><span>Primary</span>
37+
</button><button class="ant-btn ant-btn-primary" type="button">
38+
<!----><span>Primary</span>
39+
</button><button class="ant-btn ant-btn-primary" type="button">
40+
<!----><span>Primary</span>
41+
</button><button class="ant-btn ant-btn-primary" type="button">
42+
<!----><span>Primary</span>
43+
</button></div>
44+
</div>
45+
`;
46+
47+
exports[`renders ./components/flex/demo/basic.vue correctly 1`] = `
48+
<div class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical">
49+
<div class="ant-radio-group ant-radio-group-outline"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="horizontal"><span class="ant-radio-inner"></span></span><span>horizontal</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="vertical"><span class="ant-radio-inner"></span></span><span>vertical</span></label></div>
50+
<div class="ant-flex">
51+
<div style="width: 25%; height: 54px; background: rgba(22, 119, 255, 0.749);"></div>
52+
<div style="width: 25%; height: 54px; background: rgb(22, 119, 255);"></div>
53+
<div style="width: 25%; height: 54px; background: rgba(22, 119, 255, 0.749);"></div>
54+
<div style="width: 25%; height: 54px; background: rgb(22, 119, 255);"></div>
55+
</div>
56+
</div>
57+
`;
58+
59+
exports[`renders ./components/flex/demo/combination.vue correctly 1`] = `
60+
<div style="width: 620px;" class="ant-card ant-card-bordered">
61+
<!---->
62+
<!---->
63+
<div class="ant-card-body" style="padding: 0px; overflow: hidden;">
64+
<div class="ant-flex ant-flex-justify-space-between"><img alt="avatar" src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" style="display: block; width: 273px;">
65+
<div class="ant-flex ant-flex-align-flex-end ant-flex-justify-space-between ant-flex-vertical" style="padding: 32px;">
66+
<article class="ant-typography">
67+
<h3 class="ant-typography"> “antd is an enterprise-class UI design language and Vue UI library.”
68+
<!---->
69+
</h3>
70+
</article><a class="ant-btn ant-btn-primary" href="https://antdv.com" target="_blank">
71+
<!----><span>Get Start</span>
72+
</a>
73+
</div>
74+
</div>
75+
</div>
76+
<!---->
77+
</div>
78+
`;
79+
80+
exports[`renders ./components/flex/demo/gap.vue correctly 1`] = `
81+
<div class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical">
82+
<div class="ant-radio-group ant-radio-group-outline"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="small"><span class="ant-radio-inner"></span></span><span>small</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="middle"><span class="ant-radio-inner"></span></span><span>middle</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="large"><span class="ant-radio-inner"></span></span><span>large</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="customize"><span class="ant-radio-inner"></span></span><span>customize</span></label></div>
83+
<!--v-if-->
84+
<div class="ant-flex ant-flex-gap-small"><button class="ant-btn ant-btn-primary" type="button">
85+
<!----><span>Primary</span>
86+
</button><button class="ant-btn ant-btn-default" type="button">
87+
<!----><span>Default</span>
88+
</button><button class="ant-btn ant-btn-dashed" type="button">
89+
<!----><span>Dashed</span>
90+
</button><button class="ant-btn ant-btn-link" type="button">
91+
<!----><span>Link</span>
92+
</button></div>
93+
</div>
94+
`;
95+
96+
exports[`renders ./components/flex/demo/wrap.vue correctly 1`] = `
97+
<div class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"><button class="ant-btn ant-btn-primary" type="button">
98+
<!----><span>Button</span>
99+
</button><button class="ant-btn ant-btn-primary" type="button">
100+
<!----><span>Button</span>
101+
</button><button class="ant-btn ant-btn-primary" type="button">
102+
<!----><span>Button</span>
103+
</button><button class="ant-btn ant-btn-primary" type="button">
104+
<!----><span>Button</span>
105+
</button><button class="ant-btn ant-btn-primary" type="button">
106+
<!----><span>Button</span>
107+
</button><button class="ant-btn ant-btn-primary" type="button">
108+
<!----><span>Button</span>
109+
</button><button class="ant-btn ant-btn-primary" type="button">
110+
<!----><span>Button</span>
111+
</button><button class="ant-btn ant-btn-primary" type="button">
112+
<!----><span>Button</span>
113+
</button><button class="ant-btn ant-btn-primary" type="button">
114+
<!----><span>Button</span>
115+
</button><button class="ant-btn ant-btn-primary" type="button">
116+
<!----><span>Button</span>
117+
</button><button class="ant-btn ant-btn-primary" type="button">
118+
<!----><span>Button</span>
119+
</button><button class="ant-btn ant-btn-primary" type="button">
120+
<!----><span>Button</span>
121+
</button><button class="ant-btn ant-btn-primary" type="button">
122+
<!----><span>Button</span>
123+
</button><button class="ant-btn ant-btn-primary" type="button">
124+
<!----><span>Button</span>
125+
</button><button class="ant-btn ant-btn-primary" type="button">
126+
<!----><span>Button</span>
127+
</button><button class="ant-btn ant-btn-primary" type="button">
128+
<!----><span>Button</span>
129+
</button><button class="ant-btn ant-btn-primary" type="button">
130+
<!----><span>Button</span>
131+
</button><button class="ant-btn ant-btn-primary" type="button">
132+
<!----><span>Button</span>
133+
</button><button class="ant-btn ant-btn-primary" type="button">
134+
<!----><span>Button</span>
135+
</button><button class="ant-btn ant-btn-primary" type="button">
136+
<!----><span>Button</span>
137+
</button><button class="ant-btn ant-btn-primary" type="button">
138+
<!----><span>Button</span>
139+
</button><button class="ant-btn ant-btn-primary" type="button">
140+
<!----><span>Button</span>
141+
</button><button class="ant-btn ant-btn-primary" type="button">
142+
<!----><span>Button</span>
143+
</button><button class="ant-btn ant-btn-primary" type="button">
144+
<!----><span>Button</span>
145+
</button></div>
146+
`;

Diff for: components/flex/__testts__/demo.test.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import demoTest from '../../../tests/shared/demoTest';
2+
3+
demoTest('flex');

Diff for: components/flex/__testts__/index.test.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { mount } from '@vue/test-utils';
2+
import Flex from '..';
3+
import mountTest from '../../../tests/shared/mountTest';
4+
5+
describe('Flex', () => {
6+
mountTest(Flex);
7+
8+
it('Flex', () => {
9+
const wrapper = mount({
10+
render() {
11+
return <Flex justify="center">test</Flex>;
12+
},
13+
});
14+
const wrapper2 = mount({
15+
render() {
16+
return <Flex gap={100}>test</Flex>;
17+
},
18+
});
19+
expect(wrapper.classes('ant-flex')).toBeTruthy();
20+
expect(wrapper.find('.ant-flex-justify-center')).toBeTruthy();
21+
expect(wrapper2.classes('ant-flex')).toBeTruthy();
22+
expect(wrapper2.element.style.gap).toBe('100px');
23+
});
24+
25+
it('Component work', () => {
26+
const wrapper = mount({
27+
render() {
28+
return <Flex>test</Flex>;
29+
},
30+
});
31+
const wrapper2 = mount({
32+
render() {
33+
return <Flex component="span">test</Flex>;
34+
},
35+
});
36+
expect(wrapper.find('.ant-flex').element.tagName).toBe('DIV');
37+
expect(wrapper2.find('.ant-flex').element.tagName).toBe('SPAN');
38+
});
39+
40+
it('when vertical=true should stretch work', () => {
41+
const wrapper = mount({
42+
render() {
43+
return <Flex vertical>test</Flex>;
44+
},
45+
});
46+
const wrapper2 = mount({
47+
render() {
48+
return (
49+
<Flex vertical align="center">
50+
test
51+
</Flex>
52+
);
53+
},
54+
});
55+
expect(wrapper.find('.ant-flex-align-stretch')).toBeTruthy();
56+
expect(wrapper2.find('.ant-flex-align-center')).toBeTruthy();
57+
});
58+
});

Diff for: components/flex/demo/align.vue

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<docs>
2+
---
3+
order: 1
4+
title:
5+
zh-CN: 对齐方式
6+
en-US: Align
7+
---
8+
9+
## zh-CN
10+
11+
设置对齐方式。
12+
13+
## en-US
14+
15+
Set align.
16+
17+
</docs>
18+
19+
<template>
20+
<a-flex gap="middle" align="start" vertical>
21+
<p>Select justify :</p>
22+
<a-segmented v-model:value="justify" :options="justifyOptions" />
23+
<p>Select align :</p>
24+
<a-segmented v-model:value="alignItems" :options="alignOptions" />
25+
<a-flex :style="{ ...boxStyle }" :justify="justify" :align="alignItems">
26+
<a-button type="primary">Primary</a-button>
27+
<a-button type="primary">Primary</a-button>
28+
<a-button type="primary">Primary</a-button>
29+
<a-button type="primary">Primary</a-button>
30+
</a-flex>
31+
</a-flex>
32+
</template>
33+
34+
<script setup lang="ts">
35+
import { reactive, ref } from 'vue';
36+
import type { CSSProperties } from 'vue';
37+
import type { FlexProps } from 'ant-design-vue';
38+
const justifyOptions = reactive<FlexProps['justify'][]>([
39+
'flex-start',
40+
'center',
41+
'flex-end',
42+
'space-between',
43+
'space-around',
44+
'space-evenly',
45+
]);
46+
47+
const alignOptions = reactive<FlexProps['align'][]>(['flex-start', 'center', 'flex-end']);
48+
const justify = ref(justifyOptions[0]);
49+
const alignItems = ref(alignOptions[0]);
50+
const boxStyle: CSSProperties = {
51+
width: '100%',
52+
height: '120px',
53+
borderRadius: '6px',
54+
border: '1px solid #40a9ff',
55+
};
56+
</script>

Diff for: components/flex/demo/basic.vue

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<docs>
2+
---
3+
order: 0
4+
title:
5+
zh-CN: 基本布局
6+
en-US: Basic
7+
---
8+
9+
## zh-CN
10+
11+
最简单的用法。
12+
13+
## en-US
14+
15+
The basic usage.
16+
17+
</docs>
18+
19+
<template>
20+
<a-flex gap="middle" vertical>
21+
<a-radio-group v-model:value="value">
22+
<a-radio value="horizontal">horizontal</a-radio>
23+
<a-radio value="vertical">vertical</a-radio>
24+
</a-radio-group>
25+
<a-flex :vertical="value === 'vertical'">
26+
<div
27+
v-for="(item, index) in new Array(4)"
28+
:key="item"
29+
:style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"
30+
/>
31+
</a-flex>
32+
</a-flex>
33+
</template>
34+
35+
<script setup lang="ts">
36+
import { ref } from 'vue';
37+
import type { CSSProperties } from 'vue';
38+
const value = ref('horizontal');
39+
const baseStyle: CSSProperties = {
40+
width: '25%',
41+
height: '54px',
42+
};
43+
</script>

Diff for: components/flex/demo/combination.vue

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<docs>
2+
---
3+
order: 4
4+
title:
5+
zh-CN: 组合使用
6+
en-US: combination
7+
---
8+
9+
## zh-CN
10+
11+
嵌套使用,可以实现更复杂的布局。
12+
13+
## en-US
14+
15+
Nesting can achieve more complex layouts.
16+
17+
</docs>
18+
19+
<template>
20+
<a-card :style="cardStyle" :body-style="{ padding: 0, overflow: 'hidden' }">
21+
<a-flex justify="space-between">
22+
<img
23+
alt="avatar"
24+
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
25+
:style="imgStyle"
26+
/>
27+
<a-flex vertical align="flex-end" justify="space-between" :style="{ padding: '32px' }">
28+
<a-typography>
29+
<a-typography-title :level="3">
30+
“antd is an enterprise-class UI design language and Vue UI library.”
31+
</a-typography-title>
32+
</a-typography>
33+
<a-button type="primary" href="https://antdv.com" target="_blank">Get Start</a-button>
34+
</a-flex>
35+
</a-flex>
36+
</a-card>
37+
</template>
38+
39+
<script setup lang="ts">
40+
import type { CSSProperties } from 'vue';
41+
const cardStyle: CSSProperties = {
42+
width: '620px',
43+
};
44+
const imgStyle: CSSProperties = {
45+
display: 'block',
46+
width: '273px',
47+
};
48+
</script>

0 commit comments

Comments
 (0)