Skip to content

Commit fe99051

Browse files
committed
refactor: grid
1 parent a01be5c commit fe99051

File tree

10 files changed

+236
-156
lines changed

10 files changed

+236
-156
lines changed

components/_util/canUseDom.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function canUseDom() {
2+
return !!(typeof window !== 'undefined' && window.document && window.document.createElement);
3+
}
4+
5+
export default canUseDom;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { onMounted, ref } from 'vue';
2+
import { detectFlexGapSupported } from '../styleChecker';
3+
4+
export default () => {
5+
const flexible = ref(false);
6+
onMounted(() => {
7+
flexible.value = detectFlexGapSupported();
8+
});
9+
10+
return flexible;
11+
};

components/_util/styleChecker.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
const isStyleSupport = (styleName: string | Array<string>): boolean => {
2-
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
1+
import canUseDom from './canUseDom';
2+
3+
export const canUseDocElement = () => canUseDom() && window.document.documentElement;
4+
5+
export const isStyleSupport = (styleName: string | Array<string>): boolean => {
6+
if (canUseDocElement()) {
37
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
48
const { documentElement } = window.document;
59

@@ -8,6 +12,32 @@ const isStyleSupport = (styleName: string | Array<string>): boolean => {
812
return false;
913
};
1014

11-
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);
15+
let flexGapSupported: boolean | undefined;
16+
export const detectFlexGapSupported = () => {
17+
if (!canUseDocElement()) {
18+
return false;
19+
}
20+
21+
if (flexGapSupported !== undefined) {
22+
return flexGapSupported;
23+
}
24+
25+
// create flex container with row-gap set
26+
const flex = document.createElement('div');
27+
flex.style.display = 'flex';
28+
flex.style.flexDirection = 'column';
29+
flex.style.rowGap = '1px';
30+
31+
// create two, elements inside it
32+
flex.appendChild(document.createElement('div'));
33+
flex.appendChild(document.createElement('div'));
34+
35+
// append to the DOM (needed to obtain scrollHeight)
36+
document.body.appendChild(flex);
37+
flexGapSupported = flex.scrollHeight === 1; // flex container should be 1px high from the row-gap
38+
document.body.removeChild(flex);
39+
40+
return flexGapSupported;
41+
};
1242

1343
export default isStyleSupport;

components/grid/Col.tsx

Lines changed: 81 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { inject, defineComponent, HTMLAttributes, CSSProperties } from 'vue';
1+
import { inject, defineComponent, CSSProperties, ExtractPropTypes, computed } from 'vue';
22
import classNames from '../_util/classNames';
33
import PropTypes from '../_util/vue-types';
4-
import { defaultConfigProvider } from '../config-provider';
54
import { rowContextState } from './Row';
5+
import useConfigInject from '../_util/hooks/useConfigInject';
6+
import { useInjectRow } from './context';
67

78
type ColSpanType = number | string;
89

@@ -16,22 +17,6 @@ export interface ColSize {
1617
pull?: ColSpanType;
1718
}
1819

19-
export interface ColProps extends HTMLAttributes {
20-
span?: ColSpanType;
21-
order?: ColSpanType;
22-
offset?: ColSpanType;
23-
push?: ColSpanType;
24-
pull?: ColSpanType;
25-
xs?: ColSpanType | ColSize;
26-
sm?: ColSpanType | ColSize;
27-
md?: ColSpanType | ColSize;
28-
lg?: ColSpanType | ColSize;
29-
xl?: ColSpanType | ColSize;
30-
xxl?: ColSpanType | ColSize;
31-
prefixCls?: string;
32-
flex?: FlexType;
33-
}
34-
3520
function parseFlex(flex: FlexType): string {
3621
if (typeof flex === 'number') {
3722
return `${flex} ${flex} auto`;
@@ -44,16 +29,43 @@ function parseFlex(flex: FlexType): string {
4429
return flex;
4530
}
4631

47-
const ACol = defineComponent<ColProps>({
32+
const stringOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
33+
export const colSize = PropTypes.shape({
34+
span: stringOrNumber,
35+
order: stringOrNumber,
36+
offset: stringOrNumber,
37+
push: stringOrNumber,
38+
pull: stringOrNumber,
39+
}).loose;
40+
const objectOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number, colSize]);
41+
42+
const colProps = {
43+
span: stringOrNumber,
44+
order: stringOrNumber,
45+
offset: stringOrNumber,
46+
push: stringOrNumber,
47+
pull: stringOrNumber,
48+
xs: objectOrNumber,
49+
sm: objectOrNumber,
50+
md: objectOrNumber,
51+
lg: objectOrNumber,
52+
xl: objectOrNumber,
53+
xxl: objectOrNumber,
54+
prefixCls: PropTypes.string,
55+
flex: stringOrNumber,
56+
};
57+
58+
export type ColProps = Partial<ExtractPropTypes<typeof colProps>>;
59+
60+
export default defineComponent({
4861
name: 'ACol',
62+
props: colProps,
4963
setup(props, { slots }) {
50-
const configProvider = inject('configProvider', defaultConfigProvider);
51-
const rowContext = inject<rowContextState>('rowContext', {});
52-
53-
return () => {
54-
const { gutter } = rowContext;
55-
const { prefixCls: customizePrefixCls, span, order, offset, push, pull, flex } = props;
56-
const prefixCls = configProvider.getPrefixCls('col', customizePrefixCls);
64+
const { gutter, supportFlexGap, wrap } = useInjectRow();
65+
const { prefixCls, direction } = useConfigInject('col', props);
66+
const classes = computed(() => {
67+
const { span, order, offset, push, pull } = props;
68+
const pre = prefixCls.value;
5769
let sizeClassObj = {};
5870
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
5971
let sizeProps: ColSize = {};
@@ -66,83 +78,62 @@ const ACol = defineComponent<ColProps>({
6678

6779
sizeClassObj = {
6880
...sizeClassObj,
69-
[`${prefixCls}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
70-
[`${prefixCls}-${size}-order-${sizeProps.order}`]:
71-
sizeProps.order || sizeProps.order === 0,
72-
[`${prefixCls}-${size}-offset-${sizeProps.offset}`]:
73-
sizeProps.offset || sizeProps.offset === 0,
74-
[`${prefixCls}-${size}-push-${sizeProps.push}`]: sizeProps.push || sizeProps.push === 0,
75-
[`${prefixCls}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull || sizeProps.pull === 0,
81+
[`${pre}-${size}-${sizeProps.span}`]: sizeProps.span !== undefined,
82+
[`${pre}-${size}-order-${sizeProps.order}`]: sizeProps.order || sizeProps.order === 0,
83+
[`${pre}-${size}-offset-${sizeProps.offset}`]: sizeProps.offset || sizeProps.offset === 0,
84+
[`${pre}-${size}-push-${sizeProps.push}`]: sizeProps.push || sizeProps.push === 0,
85+
[`${pre}-${size}-pull-${sizeProps.pull}`]: sizeProps.pull || sizeProps.pull === 0,
86+
[`${pre}-rtl`]: direction.value === 'rtl',
7687
};
7788
});
78-
const classes = classNames(
79-
prefixCls,
89+
return classNames(
90+
pre,
8091
{
81-
[`${prefixCls}-${span}`]: span !== undefined,
82-
[`${prefixCls}-order-${order}`]: order,
83-
[`${prefixCls}-offset-${offset}`]: offset,
84-
[`${prefixCls}-push-${push}`]: push,
85-
[`${prefixCls}-pull-${pull}`]: pull,
92+
[`${pre}-${span}`]: span !== undefined,
93+
[`${pre}-order-${order}`]: order,
94+
[`${pre}-offset-${offset}`]: offset,
95+
[`${pre}-push-${push}`]: push,
96+
[`${pre}-pull-${pull}`]: pull,
8697
},
8798
sizeClassObj,
8899
);
89-
let mergedStyle: CSSProperties = {};
90-
if (gutter) {
91-
mergedStyle = {
92-
...(gutter[0] > 0
93-
? {
94-
paddingLeft: `${gutter[0] / 2}px`,
95-
paddingRight: `${gutter[0] / 2}px`,
96-
}
97-
: {}),
98-
...(gutter[1] > 0
99-
? {
100-
paddingTop: `${gutter[1] / 2}px`,
101-
paddingBottom: `${gutter[1] / 2}px`,
102-
}
103-
: {}),
104-
...mergedStyle,
105-
};
100+
});
101+
102+
const mergedStyle = computed(() => {
103+
const { flex } = props;
104+
const gutterVal = gutter.value;
105+
let style: CSSProperties = {};
106+
// Horizontal gutter use padding
107+
if (gutterVal && gutterVal[0] > 0) {
108+
const horizontalGutter = `${gutterVal[0] / 2}px`;
109+
style.paddingLeft = horizontalGutter;
110+
style.paddingRight = horizontalGutter;
106111
}
107-
if (flex) {
108-
mergedStyle.flex = parseFlex(flex);
112+
113+
// Vertical gutter use padding when gap not support
114+
if (gutterVal && gutterVal[1] > 0 && !supportFlexGap.value) {
115+
const verticalGutter = `${gutterVal[1] / 2}px`;
116+
style.paddingTop = verticalGutter;
117+
style.paddingBottom = verticalGutter;
109118
}
110119

120+
if (flex) {
121+
style.flex = parseFlex(flex);
122+
123+
// Hack for Firefox to avoid size issue
124+
// https://github.com/ant-design/ant-design/pull/20023#issuecomment-564389553
125+
if (flex === 'auto' && wrap.value === false && !style.minWidth) {
126+
style.minWidth = 0;
127+
}
128+
}
129+
return style;
130+
});
131+
return () => {
111132
return (
112-
<div class={classes} style={mergedStyle}>
133+
<div class={classes.value} style={mergedStyle.value}>
113134
{slots.default?.()}
114135
</div>
115136
);
116137
};
117138
},
118139
});
119-
120-
const stringOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
121-
122-
export const ColSize = PropTypes.shape({
123-
span: stringOrNumber,
124-
order: stringOrNumber,
125-
offset: stringOrNumber,
126-
push: stringOrNumber,
127-
pull: stringOrNumber,
128-
}).loose;
129-
130-
const objectOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number, ColSize]);
131-
132-
ACol.props = {
133-
span: stringOrNumber,
134-
order: stringOrNumber,
135-
offset: stringOrNumber,
136-
push: stringOrNumber,
137-
pull: stringOrNumber,
138-
xs: objectOrNumber,
139-
sm: objectOrNumber,
140-
md: objectOrNumber,
141-
lg: objectOrNumber,
142-
xl: objectOrNumber,
143-
xxl: objectOrNumber,
144-
prefixCls: PropTypes.string,
145-
flex: stringOrNumber,
146-
};
147-
148-
export default ACol;

0 commit comments

Comments
 (0)