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 1 commit
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
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>
47 changes: 47 additions & 0 deletions components/flex/demo/gap.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<docs>
---
order: 2
title:
zh-CN: 设置间隙
en-US: gap
---

## zh-CN

使用 `gap` 设置元素之间的间距,预设了 `small`、`middle`、`large` 三种尺寸,也可以自定义间距。

## en-US

Set the `gap` between elements, which has three preset sizes: `small`, `middle`, `large`, You can also customize the gap size.

</docs>

<template>
<a-flex gap="middle" vertical>
<a-radio-group v-model:value="gapSize">
<a-radio value="small">small</a-radio>
<a-radio value="middle">middle</a-radio>
<a-radio value="large">large</a-radio>
<a-radio value="customize">customize</a-radio>
</a-radio-group>
<template v-if="gapSize === 'customize'">
<a-slider v-model:value="customGapSize" />
</template>
<a-flex :gap="gapSize !== 'customize' ? gapSize : customGapSize">
<a-button type="primary">Primary</a-button>
<a-button>Default</a-button>
<a-button type="dashed">Dashed</a-button>
<a-button type="link">Link</a-button>
</a-flex>
</a-flex>
</template>

<script setup lang="ts">
import { ref } from 'vue';

type SizeType = 'small' | 'middle' | 'large' | undefined;

const gapSize = ref<SizeType | 'customize'>('small');

const customGapSize = ref<number>(0);
</script>
30 changes: 30 additions & 0 deletions components/flex/demo/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<demo-sort :cols="1">
<Basic />
<Align />
<Gap />
<Wrap />
<Combination />
</demo-sort>
</template>
<script lang="ts">
import Align from './align.vue';
import Basic from './basic.vue';
import Combination from './combination.vue';
import Gap from './gap.vue';
import Wrap from './wrap.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
import { defineComponent } from 'vue';
export default defineComponent({
CN,
US,
components: {
Align,
Basic,
Combination,
Gap,
Wrap,
},
});
</script>
23 changes: 23 additions & 0 deletions components/flex/demo/wrap.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<docs>
---
order: 3
title:
zh-CN: 自动换行
en-US: Wrap
---

## zh-CN

自动换行。

## en-US

Auto wrap line.

</docs>

<template>
<a-flex wrap="wrap" gap="small">
<a-button v-for="item in new Array(24)" :key="item" type="primary">Button</a-button>
</a-flex>
</template>
32 changes: 32 additions & 0 deletions components/flex/index.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
category: Components
group: Layout
title: Flex
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*SMzgSJZE_AwAAAAAAAAAAAAADrJ8AQ/original
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8yArQ43EGccAAAAAAAAAAAAADrJ8AQ/original
tag: New
---

## When To Use

- Good for setting spacing between elements.
- Suitable for setting various horizontal and vertical alignments.

### Difference with Space component

- Space is used to set the spacing between inline elements. It will add a wrapper element for each child element for inline alignment. Suitable for equidistant arrangement of multiple child elements in rows and columns.
- Flex is used to set the layout of block-level elements. It does not add a wrapper element. Suitable for layout of child elements in vertical or horizontal direction, and provides more flexibility and control.

## API

> This component is available since `[email protected]`. The default behavior of Flex in horizontal mode is to align upward, In vertical mode, aligns the stretch, You can adjust this via properties.

| Property | Description | type | Default | Version |
| --- | --- | --- | --- | --- |
| vertical | Is direction of the flex vertical, use `flex-direction: column` | boolean | `false` | |
| wrap | Set whether the element is displayed in a single line or in multiple lines | reference [flex-wrap](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap) | nowrap | |
| justify | Sets the alignment of elements in the direction of the main axis | reference [justify-content](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content) | normal | |
| align | Sets the alignment of elements in the direction of the cross axis | reference [align-items](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items) | normal | |
| flex | flex CSS shorthand properties | reference [flex](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) | normal | |
| gap | Sets the gap between grids | `small` \| `middle` \| `large` \| string \| number | - | |
| component | custom element type | Component | `div` | |
66 changes: 66 additions & 0 deletions components/flex/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { defineComponent, shallowRef } from 'vue';
import type { CSSProperties } from 'vue';
import { useConfigContextInject } from '../config-provider/context';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import useStyle from './style';
import classNames from '../_util/classNames';
import { isPresetSize } from '../_util/gapSize';
import omit from '../_util/omit';
import { withInstall } from '../_util/type';
import type { FlexProps } from './interface';
import { flexProps } from './interface';
import createFlexClassNames from './utils';

const AFlex = defineComponent({
name: 'AFlex',
inheritAttrs: false,
props: { ...flexProps },
setup(props, { slots, attrs }) {
const { flex: ctxFlex, direction: ctxDirection } = useConfigContextInject();
const { prefixCls } = useConfigInject('flex', props);
const [wrapSSR, hashId] = useStyle(prefixCls);
const flexRef = shallowRef();

return () => {
const { flex, gap, vertical = false, component: Component = 'div', ...othersProps } = props;

const mergedVertical = vertical ?? ctxFlex?.value.vertical;

const mergedCls = classNames(
attrs.class,
prefixCls.value,
hashId.value,
createFlexClassNames(prefixCls.value, props),
{
[`${prefixCls.value}-rtl`]: ctxDirection.value === 'rtl',
[`${prefixCls.value}-gap-${gap}`]: isPresetSize(gap),
[`${prefixCls.value}-vertical`]: mergedVertical,
},
);

const mergedStyle = { ...(attrs.style as CSSProperties) };

if (flex) {
mergedStyle.flex = flex;
}

if (gap && !isPresetSize(gap)) {
mergedStyle.gap = `${gap}px`;
}

return wrapSSR(
<Component
ref={flexRef.value}
class={mergedCls}
style={mergedStyle}
{...omit(othersProps, ['justify', 'wrap', 'align'])}
>
{slots.default?.()}
</Component>,
);
};
},
});

export default withInstall(AFlex);
export type { FlexProps };
Loading