Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a15bb9c

Browse files
refactor(flex): use SFC (#8308)
* refactor(flex): use SFC * test: add unit tests
1 parent 5cc4a63 commit a15bb9c

File tree

12 files changed

+535
-0
lines changed

12 files changed

+535
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<template>
2+
<a-flex gap="middle" vertical>
3+
<label>
4+
Select axis:
5+
<select v-model="axis">
6+
<option v-for="item in axisOptions" :key="item">{{ item }}</option>
7+
</select>
8+
</label>
9+
<a-flex :vertical="axis === 'vertical'">
10+
<div
11+
v-for="(item, index) in new Array(4)"
12+
:key="item"
13+
:style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"
14+
/>
15+
</a-flex>
16+
<hr/>
17+
<label>
18+
Select justify:
19+
<select v-model="justify">
20+
<option v-for="item in justifyOptions" :key="item">{{ item }}</option>
21+
</select>
22+
</label>
23+
<label>
24+
Select align:
25+
<select v-model="align">
26+
<option v-for="item in alignOptions" :key="item">{{ item }}</option>
27+
</select>
28+
</label>
29+
<a-flex :style="{ ...boxStyle }" :justify="justify" :align="align">
30+
<a-button variant="solid">Primary</a-button>
31+
<a-button variant="solid">Primary</a-button>
32+
<a-button variant="solid">Primary</a-button>
33+
<a-button variant="solid">Primary</a-button>
34+
</a-flex>
35+
<hr/>
36+
<a-flex gap="middle" vertical>
37+
<label>
38+
Select gap size:
39+
<select v-model="gapSize">
40+
<option v-for="item in gapSizeOptions" :key="item">{{ item }}</option>
41+
</select>
42+
</label>
43+
<a-flex :gap="gapSize">
44+
<a-button variant="solid">Primary</a-button>
45+
<a-button>Default</a-button>
46+
<a-button variant="dashed">Dashed</a-button>
47+
<a-button variant="link">Link</a-button>
48+
</a-flex>
49+
</a-flex>
50+
<hr/>
51+
<label>
52+
Auto wrap:
53+
</label>
54+
<a-flex wrap="wrap" gap="small">
55+
<a-button v-for="item in new Array(24)" :key="item" variant="solid">Button</a-button>
56+
</a-flex>
57+
</a-flex>
58+
</template>
59+
60+
<script setup lang="ts">
61+
import type { CSSProperties } from 'vue';
62+
import { ref, reactive } from 'vue';
63+
64+
const baseStyle: CSSProperties = {
65+
width: '25%',
66+
height: '54px',
67+
};
68+
const boxStyle: CSSProperties = {
69+
width: '100%',
70+
height: '120px',
71+
borderRadius: '6px',
72+
border: '1px solid #40a9ff',
73+
};
74+
75+
const axisOptions = reactive(['horizontal', 'vertical']);
76+
const axis = ref(axisOptions[0]);
77+
78+
const justifyOptions = reactive([
79+
'flex-start',
80+
'center',
81+
'flex-end',
82+
'space-between',
83+
'space-around',
84+
'space-evenly',
85+
]);
86+
const justify = ref(justifyOptions[0]);
87+
88+
const alignOptions = reactive(['flex-start', 'center', 'flex-end']);
89+
const align = ref(alignOptions[0]);
90+
91+
const gapSizeOptions = reactive(['small', 'middle', 'large']);
92+
const gapSize = ref(gapSizeOptions[0]);
93+
</script>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script setup lang="ts">
2+
import type { CSSProperties } from 'vue'
3+
import { computed, withDefaults } from 'vue'
4+
import { type FlexProps, flexDefaultProps } from './meta'
5+
import { isPresetSize } from '@/utils/gapSize'
6+
import createFlexClassNames from './utils'
7+
8+
defineOptions({ name: 'AFlex' })
9+
const props = withDefaults(defineProps<FlexProps>(), flexDefaultProps)
10+
11+
const mergedCls = computed(() => [
12+
createFlexClassNames(props.prefixCls, props),
13+
{
14+
'ant-flex': true,
15+
'ant-flex-vertical': props.vertical,
16+
'ant-flex-rtl': false,
17+
[`ant-flex-gap-${props.gap}`]: isPresetSize(props.gap),
18+
}
19+
])
20+
21+
const mergedStyle = computed(() => {
22+
const style: CSSProperties = {}
23+
24+
if (props.flex) {
25+
style.flex = props.flex
26+
}
27+
28+
if (props.gap && !isPresetSize(props.gap)) {
29+
style.gap = `${props.gap}px`
30+
}
31+
32+
return style
33+
})
34+
</script>
35+
36+
<template>
37+
<component :is="componentTag" :class="[$attrs.class, mergedCls]" :style="[$attrs.style, mergedStyle]" v-bind="$attrs">
38+
<slot />
39+
</component>
40+
</template>
41+
42+
<style scoped></style>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`Flex > should render correctly 1`] = `
4+
"<div class="ant-flex">
5+
<div>test</div>
6+
</div>"
7+
`;
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import { Flex } from '@ant-design-vue/ui'
3+
import { mount } from '@vue/test-utils'
4+
5+
describe('Flex', () => {
6+
it('should render correctly', () => {
7+
const wrapper = mount(Flex, {
8+
slots: {
9+
default: `<div>test</div>`,
10+
},
11+
});
12+
13+
expect(wrapper.html()).toMatchSnapshot();
14+
});
15+
16+
it('Flex', () => {
17+
const wrapper = mount(Flex, {
18+
props: {
19+
justify: 'center'
20+
},
21+
slots: {
22+
default: `<div>test</div>`
23+
},
24+
});
25+
26+
const wrapper3 = mount(Flex, {
27+
props: {
28+
flex: '0 1 auto',
29+
},
30+
slots: {
31+
default: `<div>test</div>`,
32+
},
33+
});
34+
35+
expect(wrapper.classes('ant-flex')).toBeTruthy();
36+
expect(wrapper.find('.ant-flex-justify-center')).toBeTruthy();
37+
expect(wrapper3.classes('ant-flex')).toBeTruthy();
38+
expect(wrapper3.element.style.flex).toBe('0 1 auto');
39+
});
40+
41+
describe('Props: gap', () => {
42+
it('support string', () => {
43+
const wrapper = mount(Flex, {
44+
props: {
45+
gap: 'inherit',
46+
},
47+
slots: {
48+
default: `<div>test</div>`,
49+
},
50+
});
51+
expect(wrapper.classes('ant-flex')).toBeTruthy();
52+
expect(wrapper.element.style.gap).toBe('inherit');
53+
});
54+
55+
it('support number', () => {
56+
const wrapper = mount(Flex, {
57+
props: {
58+
gap: '100',
59+
},
60+
slots: {
61+
default: `<div>test</div>`,
62+
},
63+
});
64+
expect(wrapper.classes('ant-flex')).toBeTruthy();
65+
expect(wrapper.element.style.gap).toBe('100px');
66+
});
67+
68+
it('support preset size', () => {
69+
const wrapper = mount(Flex, {
70+
props: {
71+
gap: 'small',
72+
},
73+
slots: {
74+
default: `<div>test</div>`,
75+
},
76+
});
77+
78+
expect(wrapper.classes('ant-flex')).toBeTruthy();
79+
expect(wrapper.classes('ant-flex-gap-small')).toBeTruthy();
80+
});
81+
});
82+
83+
it('Component work', () => {
84+
const wrapper = mount(Flex, {
85+
slots: {
86+
default: `<div>test</div>`
87+
},
88+
});
89+
90+
const wrapper2 = mount(Flex, {
91+
props: {
92+
componentTag: 'span'
93+
},
94+
slots: {
95+
default: `<div>test</div>`
96+
},
97+
});
98+
99+
expect(wrapper.find('.ant-flex').element.tagName).toBe('DIV');
100+
expect(wrapper2.find('.ant-flex').element.tagName).toBe('SPAN');
101+
});
102+
103+
it('when vertical=true should stretch work', () => {
104+
const wrapper = mount(Flex, {
105+
props: {
106+
vertical: true
107+
},
108+
slots: {
109+
default: `<div>test</div>`
110+
},
111+
});
112+
113+
const wrapper2 = mount(Flex, {
114+
props: {
115+
vertical: true,
116+
align: 'center',
117+
},
118+
slots: {
119+
default: `<div>test</div>`,
120+
},
121+
});
122+
123+
expect(wrapper.find('.ant-flex-align-stretch')).toBeTruthy();
124+
expect(wrapper2.find('.ant-flex-align-center')).toBeTruthy();
125+
});
126+
127+
it('wrap prop shouled support boolean', () => {
128+
const wrapper = mount(Flex, {
129+
props: {
130+
wrap: 'wrap',
131+
},
132+
slots: {
133+
default: `<div>test</div>`,
134+
},
135+
});
136+
137+
const wrapper2 = mount(Flex, {
138+
props: {
139+
wrap: true,
140+
},
141+
slots: {
142+
default: `<div>test</div>`,
143+
},
144+
});
145+
146+
expect(wrapper.classes('ant-flex-wrap-wrap')).toBeTruthy();
147+
expect(wrapper2.classes('ant-flex-wrap-wrap')).toBeTruthy();
148+
})
149+
})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { App, Plugin } from 'vue'
2+
import Flex from './Flex.vue'
3+
import './style/index.css'
4+
5+
6+
export { default as Flex } from './Flex.vue'
7+
export * from './meta'
8+
9+
Flex.install = function (app: App) {
10+
app.component('AFlex', Flex)
11+
return app
12+
}
13+
14+
export default Flex as typeof Flex & Plugin
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { CSSProperties } from "vue"
2+
3+
type SizeType = 'small' | 'middle' | 'large' | undefined
4+
5+
export type FlexProps = {
6+
prefixCls?: string
7+
rootClassName?: string
8+
vertical?: boolean
9+
wrap?: CSSProperties['flexWrap'] | boolean
10+
justify?: CSSProperties['justifyContent']
11+
align?: CSSProperties['alignItems']
12+
flex?: CSSProperties['flex']
13+
gap?: CSSProperties['gap'] | SizeType
14+
componentTag?: any
15+
}
16+
17+
export const flexDefaultProps = {
18+
prefixCls: 'ant-flex',
19+
componentTag: 'div',
20+
} as const

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /