Skip to content

feat(Flex): New component #7052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions components/_util/gapSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { SizeType } from '../config-provider/SizeContext';

export function isPresetSize(size?: SizeType | string | number): size is SizeType {
return ['small', 'middle', 'large'].includes(size as string);
}

export function isValidGapNumber(size?: SizeType | string | number): size is number {
if (!size) {
// 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.
return false;
}
return typeof size === 'number' && !Number.isNaN(size);
}
2 changes: 2 additions & 0 deletions components/_util/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ export function someType<T>(types?: any[], defaultVal?: T) {
}

export type CustomSlotsType<T> = SlotsType<T>;

export type AnyObject = Record<PropertyKey, any>;
3 changes: 3 additions & 0 deletions components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,6 @@ export { default as Tour } from './tour';

export type { AppProps } from './app';
export { default as App } from './app';

export type { FlexProps } from './flex';
export { default as Flex } from './flex';
3 changes: 3 additions & 0 deletions components/config-provider/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ export interface ConfigProviderInnerProps {
wave?: ComputedRef<{
disabled?: boolean;
}>;
flex?: ComputedRef<{
vertical?: boolean;
}>;
}

export const configProviderKey: InjectionKey<ConfigProviderInnerProps> = Symbol('configProvider');
Expand Down
146 changes: 146 additions & 0 deletions components/flex/__testts__/__snapshots__/demo.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders ./components/flex/demo/align.vue correctly 1`] = `
<div class="ant-flex ant-flex-align-start ant-flex-gap-middle ant-flex-vertical">
<p>Select justify :</p>
<div class="ant-segmented ">
<div class="ant-segmented-group">
<!----><label class="ant-segmented-item ant-segmented-item-selected"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="flex-start">flex-start</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="center">center</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="flex-end">flex-end</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="space-between">space-between</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="space-around">space-around</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="space-evenly">space-evenly</div>
</label>
</div>
</div>
<p>Select align :</p>
<div class="ant-segmented ">
<div class="ant-segmented-group">
<!----><label class="ant-segmented-item ant-segmented-item-selected"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="flex-start">flex-start</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="center">center</div>
</label><label class="ant-segmented-item"><input class="ant-segmented-item-input" type="radio">
<div class="ant-segmented-item-label" title="flex-end">flex-end</div>
</label>
</div>
</div>
<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">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button></div>
</div>
`;

exports[`renders ./components/flex/demo/basic.vue correctly 1`] = `
<div class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical">
<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>
<div class="ant-flex">
<div style="width: 25%; height: 54px; background: rgba(22, 119, 255, 0.749);"></div>
<div style="width: 25%; height: 54px; background: rgb(22, 119, 255);"></div>
<div style="width: 25%; height: 54px; background: rgba(22, 119, 255, 0.749);"></div>
<div style="width: 25%; height: 54px; background: rgb(22, 119, 255);"></div>
</div>
</div>
`;

exports[`renders ./components/flex/demo/combination.vue correctly 1`] = `
<div style="width: 620px;" class="ant-card ant-card-bordered">
<!---->
<!---->
<div class="ant-card-body" style="padding: 0px; overflow: hidden;">
<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;">
<div class="ant-flex ant-flex-align-flex-end ant-flex-justify-space-between ant-flex-vertical" style="padding: 32px;">
<article class="ant-typography">
<h3 class="ant-typography"> “antd is an enterprise-class UI design language and Vue UI library.”
<!---->
</h3>
</article><a class="ant-btn ant-btn-primary" href="https://antdv.com" target="_blank">
<!----><span>Get Start</span>
</a>
</div>
</div>
</div>
<!---->
</div>
`;

exports[`renders ./components/flex/demo/gap.vue correctly 1`] = `
<div class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical">
<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>
<!--v-if-->
<div class="ant-flex ant-flex-gap-small"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Primary</span>
</button><button class="ant-btn ant-btn-default" type="button">
<!----><span>Default</span>
</button><button class="ant-btn ant-btn-dashed" type="button">
<!----><span>Dashed</span>
</button><button class="ant-btn ant-btn-link" type="button">
<!----><span>Link</span>
</button></div>
</div>
`;

exports[`renders ./components/flex/demo/wrap.vue correctly 1`] = `
<div class="ant-flex ant-flex-wrap-wrap ant-flex-gap-small"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Button</span>
</button></div>
`;
3 changes: 3 additions & 0 deletions components/flex/__testts__/demo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';

demoTest('flex');
58 changes: 58 additions & 0 deletions components/flex/__testts__/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { mount } from '@vue/test-utils';
import Flex from '..';
import mountTest from '../../../tests/shared/mountTest';

describe('Flex', () => {
mountTest(Flex);

it('Flex', () => {
const wrapper = mount({
render() {
return <Flex justify="center">test</Flex>;
},
});
const wrapper2 = mount({
render() {
return <Flex gap={100}>test</Flex>;
},
});
expect(wrapper.classes('ant-flex')).toBeTruthy();
expect(wrapper.find('.ant-flex-justify-center')).toBeTruthy();
expect(wrapper2.classes('ant-flex')).toBeTruthy();
expect(wrapper2.element.style.gap).toBe('100px');
});

it('Component work', () => {
const wrapper = mount({
render() {
return <Flex>test</Flex>;
},
});
const wrapper2 = mount({
render() {
return <Flex component="span">test</Flex>;
},
});
expect(wrapper.find('.ant-flex').element.tagName).toBe('DIV');
expect(wrapper2.find('.ant-flex').element.tagName).toBe('SPAN');
});

it('when vertical=true should stretch work', () => {
const wrapper = mount({
render() {
return <Flex vertical>test</Flex>;
},
});
const wrapper2 = mount({
render() {
return (
<Flex vertical align="center">
test
</Flex>
);
},
});
expect(wrapper.find('.ant-flex-align-stretch')).toBeTruthy();
expect(wrapper2.find('.ant-flex-align-center')).toBeTruthy();
});
});
56 changes: 56 additions & 0 deletions components/flex/demo/align.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<docs>
---
order: 1
title:
zh-CN: 对齐方式
en-US: Align
---

## zh-CN

设置对齐方式。

## en-US

Set align.

</docs>

<template>
<a-flex gap="middle" align="start" vertical>
<p>Select justify :</p>
<a-segmented v-model:value="justify" :options="justifyOptions" />
<p>Select align :</p>
<a-segmented v-model:value="alignItems" :options="alignOptions" />
<a-flex :style="{ ...boxStyle }" :justify="justify" :align="alignItems">
<a-button type="primary">Primary</a-button>
<a-button type="primary">Primary</a-button>
<a-button type="primary">Primary</a-button>
<a-button type="primary">Primary</a-button>
</a-flex>
</a-flex>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';
import type { CSSProperties } from 'vue';
import type { FlexProps } from 'ant-design-vue';
const justifyOptions = reactive<FlexProps['justify'][]>([
'flex-start',
'center',
'flex-end',
'space-between',
'space-around',
'space-evenly',
]);

const alignOptions = reactive<FlexProps['align'][]>(['flex-start', 'center', 'flex-end']);
const justify = ref(justifyOptions[0]);
const alignItems = ref(alignOptions[0]);
const boxStyle: CSSProperties = {
width: '100%',
height: '120px',
borderRadius: '6px',
border: '1px solid #40a9ff',
};
</script>
43 changes: 43 additions & 0 deletions components/flex/demo/basic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<docs>
---
order: 0
title:
zh-CN: 基本布局
en-US: Basic
---

## zh-CN

最简单的用法。

## en-US

The basic usage.

</docs>

<template>
<a-flex gap="middle" vertical>
<a-radio-group v-model:value="value">
<a-radio value="horizontal">horizontal</a-radio>
<a-radio value="vertical">vertical</a-radio>
</a-radio-group>
<a-flex :vertical="value === 'vertical'">
<div
v-for="(item, index) in new Array(4)"
:key="item"
:style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"
/>
</a-flex>
</a-flex>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import type { CSSProperties } from 'vue';
const value = ref('horizontal');
const baseStyle: CSSProperties = {
width: '25%',
height: '54px',
};
</script>
48 changes: 48 additions & 0 deletions components/flex/demo/combination.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<docs>
---
order: 4
title:
zh-CN: 组合使用
en-US: combination
---

## zh-CN

嵌套使用,可以实现更复杂的布局。

## en-US

Nesting can achieve more complex layouts.

</docs>

<template>
<a-card :style="cardStyle" :body-style="{ padding: 0, overflow: 'hidden' }">
<a-flex justify="space-between">
<img
alt="avatar"
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
:style="imgStyle"
/>
<a-flex vertical align="flex-end" justify="space-between" :style="{ padding: '32px' }">
<a-typography>
<a-typography-title :level="3">
“antd is an enterprise-class UI design language and Vue UI library.”
</a-typography-title>
</a-typography>
<a-button type="primary" href="https://antdv.com" target="_blank">Get Start</a-button>
</a-flex>
</a-flex>
</a-card>
</template>

<script setup lang="ts">
import type { CSSProperties } from 'vue';
const cardStyle: CSSProperties = {
width: '620px',
};
const imgStyle: CSSProperties = {
display: 'block',
width: '273px',
};
</script>
Loading