gi-component 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/dist/index.es.js +2241 -0
- package/dist/dist/index.es.js.map +1 -0
- package/dist/dist/index.umd.js +2 -0
- package/dist/dist/index.umd.js.map +1 -0
- package/dist/gi.css +1 -0
- package/dist/index.d.ts +1 -0
- package/package.json +56 -0
- package/packages/components/button/index.ts +5 -0
- package/packages/components/button/src/button.vue +59 -0
- package/packages/components/button/src/type.ts +15 -0
- package/packages/components/card/index.ts +5 -0
- package/packages/components/card/src/card.vue +166 -0
- package/packages/components/card/src/type.ts +12 -0
- package/packages/components/dialog/index.ts +6 -0
- package/packages/components/dialog/src/dialog.ts +87 -0
- package/packages/components/dialog/src/dialog.vue +122 -0
- package/packages/components/dialog/src/type.ts +16 -0
- package/packages/components/edit-table/index.ts +5 -0
- package/packages/components/edit-table/src/edit-table.vue +207 -0
- package/packages/components/edit-table/src/type.ts +69 -0
- package/packages/components/form/index.ts +5 -0
- package/packages/components/form/src/form.vue +465 -0
- package/packages/components/form/src/type.ts +98 -0
- package/packages/components/grid/index.ts +8 -0
- package/packages/components/grid/src/context.ts +30 -0
- package/packages/components/grid/src/grid-item.vue +143 -0
- package/packages/components/grid/src/grid.vue +151 -0
- package/packages/components/grid/src/hook/use-index.ts +63 -0
- package/packages/components/grid/src/hook/use-responsive-state.ts +66 -0
- package/packages/components/grid/src/hook/use-responsive-value.ts +36 -0
- package/packages/components/grid/src/interface.ts +74 -0
- package/packages/components/grid/src/type.ts +0 -0
- package/packages/components/grid/src/utils/global-config.ts +6 -0
- package/packages/components/grid/src/utils/index.ts +73 -0
- package/packages/components/grid/src/utils/is.ts +9 -0
- package/packages/components/grid/src/utils/responsive-observe.ts +135 -0
- package/packages/components/input-group/index.ts +5 -0
- package/packages/components/input-group/src/input-group.vue +92 -0
- package/packages/components/input-group/src/type.ts +1 -0
- package/packages/components/input-search/index.ts +5 -0
- package/packages/components/input-search/src/input-search.vue +62 -0
- package/packages/components/input-search/src/type.ts +6 -0
- package/packages/components/page-layout/index.ts +5 -0
- package/packages/components/page-layout/src/page-layout.vue +180 -0
- package/packages/components/page-layout/src/split-button.vue +106 -0
- package/packages/components/page-layout/src/type.ts +12 -0
- package/packages/components/table/index.ts +5 -0
- package/packages/components/table/src/TableColumn.vue +49 -0
- package/packages/components/table/src/table.vue +85 -0
- package/packages/components/table/src/type.ts +22 -0
- package/packages/components/tabs/index.ts +5 -0
- package/packages/components/tabs/src/tabs.vue +148 -0
- package/packages/components/tabs/src/type.ts +15 -0
- package/packages/components.d.ts +26 -0
- package/packages/hooks/index.ts +1 -0
- package/packages/hooks/useBemClass.ts +11 -0
- package/packages/index.ts +78 -0
- package/packages/styles/index.scss +176 -0
- package/packages/styles/var.scss +1 -0
- package/packages/utils/createSelectDialog.ts +67 -0
- package/packages/utils/index.ts +1 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="domRef" :class="classNames" :style="style">
|
|
3
|
+
<slot :overflow="overflow" />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { PropType } from 'vue';
|
|
9
|
+
import type { ResponsiveValue } from './interface';
|
|
10
|
+
import {
|
|
11
|
+
computed,
|
|
12
|
+
defineComponent,
|
|
13
|
+
inject,
|
|
14
|
+
onUnmounted,
|
|
15
|
+
ref,
|
|
16
|
+
toRefs,
|
|
17
|
+
watchEffect
|
|
18
|
+
} from 'vue';
|
|
19
|
+
import {
|
|
20
|
+
GridContextInjectionKey,
|
|
21
|
+
GridDataCollectorInjectionKey
|
|
22
|
+
} from './context';
|
|
23
|
+
import { useIndex } from './hook/use-index';
|
|
24
|
+
import { useResponsiveState } from './hook/use-responsive-state';
|
|
25
|
+
import { resolveItemData } from './utils';
|
|
26
|
+
import { getPrefixCls } from './utils/global-config';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @version 2.15.0
|
|
30
|
+
* @zh 响应式配置从 `2.18.0` 开始支持,具体配置 [ResponsiveValue](#responsivevalue)
|
|
31
|
+
* @en Responsive configuration has been supported since `2.18.0`, the specific configuration [ResponsiveValue](#responsivevalue)
|
|
32
|
+
*/
|
|
33
|
+
export default defineComponent({
|
|
34
|
+
name: 'GridItem',
|
|
35
|
+
props: {
|
|
36
|
+
/**
|
|
37
|
+
* @zh 跨越的格数
|
|
38
|
+
* @en Number of grids spanned
|
|
39
|
+
*/
|
|
40
|
+
span: {
|
|
41
|
+
type: [Number, Object] as PropType<number | ResponsiveValue>,
|
|
42
|
+
default: 1
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* @zh 左侧的间隔格数
|
|
46
|
+
* @en Number of grids on the left
|
|
47
|
+
*/
|
|
48
|
+
offset: {
|
|
49
|
+
type: [Number, Object] as PropType<number | ResponsiveValue>,
|
|
50
|
+
default: 0
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* @zh 是否是后缀元素
|
|
54
|
+
* @en Is it a suffix element
|
|
55
|
+
*/
|
|
56
|
+
suffix: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
setup(props) {
|
|
62
|
+
const prefixCls = getPrefixCls('grid-item');
|
|
63
|
+
const domRef = ref<HTMLDivElement>();
|
|
64
|
+
const { computedIndex } = useIndex({
|
|
65
|
+
itemRef: domRef,
|
|
66
|
+
selector: `.${prefixCls}`
|
|
67
|
+
});
|
|
68
|
+
const gridContext = inject(GridContextInjectionKey, {
|
|
69
|
+
overflow: false,
|
|
70
|
+
displayIndexList: [],
|
|
71
|
+
cols: 24,
|
|
72
|
+
colGap: 0
|
|
73
|
+
});
|
|
74
|
+
const gridDataCollector = inject(GridDataCollectorInjectionKey);
|
|
75
|
+
const visible = computed(() =>
|
|
76
|
+
gridContext?.displayIndexList?.includes(computedIndex.value)
|
|
77
|
+
);
|
|
78
|
+
const { span: propSpan, offset: propOffset } = toRefs(props);
|
|
79
|
+
const rSpan = useResponsiveState(propSpan, 1);
|
|
80
|
+
const rOffset = useResponsiveState(propOffset, 0);
|
|
81
|
+
const itemData = computed(() =>
|
|
82
|
+
resolveItemData(gridContext.cols, {
|
|
83
|
+
...props,
|
|
84
|
+
span: rSpan.value,
|
|
85
|
+
offset: rOffset.value
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const classNames = computed(() => [prefixCls]);
|
|
90
|
+
const offsetStyle = computed(() => {
|
|
91
|
+
const { offset, span } = itemData.value;
|
|
92
|
+
const { colGap } = gridContext;
|
|
93
|
+
if (offset > 0) {
|
|
94
|
+
const oneSpan = `(100% - ${colGap * (span - 1)}px) / ${span}`;
|
|
95
|
+
return {
|
|
96
|
+
'margin-left': `calc((${oneSpan} * ${offset}) + ${colGap * offset}px)`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {};
|
|
100
|
+
});
|
|
101
|
+
const columnStart = computed(() => {
|
|
102
|
+
const { suffix, span } = itemData.value;
|
|
103
|
+
const { cols } = gridContext;
|
|
104
|
+
if (suffix) {
|
|
105
|
+
return `${cols - span + 1}`;
|
|
106
|
+
}
|
|
107
|
+
return `span ${span}`;
|
|
108
|
+
});
|
|
109
|
+
const style = computed(() => {
|
|
110
|
+
const { span } = itemData.value;
|
|
111
|
+
if (domRef.value) {
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
'grid-column': `${columnStart.value} / span ${span}`
|
|
115
|
+
},
|
|
116
|
+
offsetStyle.value,
|
|
117
|
+
!visible.value || span === 0 ? { display: 'none' } : {}
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
return [];
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
watchEffect(() => {
|
|
124
|
+
if (computedIndex.value !== -1) {
|
|
125
|
+
gridDataCollector?.collectItemData(computedIndex.value, itemData.value);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
onUnmounted(() => {
|
|
130
|
+
if (computedIndex.value !== -1) {
|
|
131
|
+
gridDataCollector?.removeItemData(computedIndex.value);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
classNames,
|
|
137
|
+
style,
|
|
138
|
+
domRef,
|
|
139
|
+
overflow: computed(() => gridContext.overflow)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
</script>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="classNames" :style="style">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { PropType } from 'vue';
|
|
9
|
+
import type { GridItemData, ResponsiveValue } from './interface';
|
|
10
|
+
import {
|
|
11
|
+
computed,
|
|
12
|
+
defineComponent,
|
|
13
|
+
provide,
|
|
14
|
+
reactive,
|
|
15
|
+
toRefs,
|
|
16
|
+
watchEffect
|
|
17
|
+
} from 'vue';
|
|
18
|
+
import {
|
|
19
|
+
GridContextInjectionKey,
|
|
20
|
+
GridDataCollectorInjectionKey
|
|
21
|
+
} from './context';
|
|
22
|
+
import { useResponsiveState } from './hook/use-responsive-state';
|
|
23
|
+
import { setItemVisible } from './utils';
|
|
24
|
+
import { getPrefixCls } from './utils/global-config';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @version 2.15.0
|
|
28
|
+
* @zh 响应式配置从 `2.18.0` 开始支持,具体配置 [ResponsiveValue](#responsivevalue)
|
|
29
|
+
* @en Responsive configuration has been supported since `2.18.0`, the specific configuration [ResponsiveValue](#responsivevalue)
|
|
30
|
+
*/
|
|
31
|
+
export default defineComponent({
|
|
32
|
+
name: 'Grid',
|
|
33
|
+
props: {
|
|
34
|
+
/**
|
|
35
|
+
* @zh 每一行展示的列数
|
|
36
|
+
* @en Number of columns displayed in each row
|
|
37
|
+
*/
|
|
38
|
+
cols: {
|
|
39
|
+
type: [Number, Object] as PropType<number | ResponsiveValue>,
|
|
40
|
+
default: 24
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* @zh 行与行之间的间距
|
|
44
|
+
* @en The space in row-to-row
|
|
45
|
+
*/
|
|
46
|
+
rowGap: {
|
|
47
|
+
type: [Number, Object] as PropType<number | ResponsiveValue>,
|
|
48
|
+
default: 0
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* @zh 列与列之间的间距
|
|
52
|
+
* @en The space in column-to-column
|
|
53
|
+
*/
|
|
54
|
+
colGap: {
|
|
55
|
+
type: [Number, Object] as PropType<number | ResponsiveValue>,
|
|
56
|
+
default: 0
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* @zh 是否折叠
|
|
60
|
+
* @en Whether to collapsed
|
|
61
|
+
*/
|
|
62
|
+
collapsed: {
|
|
63
|
+
type: Boolean,
|
|
64
|
+
default: false
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* @zh 折叠时显示的行数
|
|
68
|
+
* @en Number of rows displayed when collapsed
|
|
69
|
+
*/
|
|
70
|
+
collapsedRows: {
|
|
71
|
+
type: Number,
|
|
72
|
+
default: 1
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
setup(props) {
|
|
76
|
+
const {
|
|
77
|
+
cols: propCols,
|
|
78
|
+
rowGap: propRowGap,
|
|
79
|
+
colGap: propColGap,
|
|
80
|
+
collapsedRows,
|
|
81
|
+
collapsed
|
|
82
|
+
} = toRefs(props);
|
|
83
|
+
const cols = useResponsiveState(propCols, 24);
|
|
84
|
+
const colGap = useResponsiveState(propColGap, 0);
|
|
85
|
+
const rowGap = useResponsiveState(propRowGap, 0);
|
|
86
|
+
const prefixCls = getPrefixCls('grid');
|
|
87
|
+
const classNames = computed(() => [prefixCls]);
|
|
88
|
+
const style = computed(() => [
|
|
89
|
+
{
|
|
90
|
+
gap: `${rowGap.value}px ${colGap.value}px`,
|
|
91
|
+
'grid-template-columns': `repeat(${cols.value}, minmax(0px, 1fr))`
|
|
92
|
+
}
|
|
93
|
+
]);
|
|
94
|
+
const itemDataMap = reactive<Map<number, GridItemData>>(new Map());
|
|
95
|
+
const itemDataList = computed(() => {
|
|
96
|
+
const list: GridItemData[] = [];
|
|
97
|
+
for (const [index, itemData] of itemDataMap.entries()) {
|
|
98
|
+
list[index] = itemData;
|
|
99
|
+
}
|
|
100
|
+
return list;
|
|
101
|
+
});
|
|
102
|
+
const gridContext = reactive<{
|
|
103
|
+
overflow: boolean;
|
|
104
|
+
displayIndexList: number[];
|
|
105
|
+
cols: number;
|
|
106
|
+
colGap: number;
|
|
107
|
+
}>({
|
|
108
|
+
overflow: false,
|
|
109
|
+
displayIndexList: [],
|
|
110
|
+
cols: cols.value,
|
|
111
|
+
colGap: colGap.value
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
watchEffect(() => {
|
|
115
|
+
gridContext.cols = cols.value;
|
|
116
|
+
gridContext.colGap = colGap.value;
|
|
117
|
+
});
|
|
118
|
+
watchEffect(() => {
|
|
119
|
+
const displayInfo = setItemVisible({
|
|
120
|
+
cols: cols.value,
|
|
121
|
+
collapsed: collapsed.value,
|
|
122
|
+
collapsedRows: collapsedRows.value,
|
|
123
|
+
itemDataList: itemDataList.value
|
|
124
|
+
});
|
|
125
|
+
gridContext.overflow = displayInfo.overflow;
|
|
126
|
+
gridContext.displayIndexList = displayInfo.displayIndexList;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
provide(GridContextInjectionKey, gridContext);
|
|
130
|
+
provide(GridDataCollectorInjectionKey, {
|
|
131
|
+
collectItemData(index, itemData) {
|
|
132
|
+
itemDataMap.set(index, itemData);
|
|
133
|
+
},
|
|
134
|
+
removeItemData(index) {
|
|
135
|
+
itemDataMap.delete(index);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
classNames,
|
|
141
|
+
style
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<style lang="scss" scoped>
|
|
148
|
+
.gi-grid {
|
|
149
|
+
display: grid;
|
|
150
|
+
}
|
|
151
|
+
</style>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import { computed, onMounted, onUpdated, ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
function isUndefined(obj: any): obj is undefined {
|
|
5
|
+
return obj === undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function useIndex({
|
|
9
|
+
itemRef,
|
|
10
|
+
selector,
|
|
11
|
+
index,
|
|
12
|
+
parentClassName
|
|
13
|
+
}: {
|
|
14
|
+
itemRef: Ref<HTMLElement | undefined>;
|
|
15
|
+
selector: string;
|
|
16
|
+
index?: Ref<number | undefined>;
|
|
17
|
+
parentClassName?: string;
|
|
18
|
+
}) {
|
|
19
|
+
const _index = ref(-1);
|
|
20
|
+
const computedIndex = computed(() => index?.value ?? _index.value);
|
|
21
|
+
|
|
22
|
+
const parent = ref<HTMLElement>();
|
|
23
|
+
|
|
24
|
+
const getParent = () => {
|
|
25
|
+
let parent = itemRef.value?.parentElement ?? undefined;
|
|
26
|
+
if (parentClassName) {
|
|
27
|
+
while (parent && !parent.className.includes(parentClassName)) {
|
|
28
|
+
parent = parent.parentElement ?? undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return parent;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getIndex = () => {
|
|
35
|
+
if (isUndefined(index?.value) && parent.value && itemRef.value) {
|
|
36
|
+
const index = Array.from(parent.value.querySelectorAll(selector)).indexOf(
|
|
37
|
+
itemRef.value
|
|
38
|
+
);
|
|
39
|
+
if (index !== _index.value) {
|
|
40
|
+
_index.value = index;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
watch(itemRef, () => {
|
|
46
|
+
if (itemRef.value && !parent.value) {
|
|
47
|
+
parent.value = getParent();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
onMounted(() => {
|
|
52
|
+
if (itemRef.value) {
|
|
53
|
+
parent.value = getParent();
|
|
54
|
+
}
|
|
55
|
+
getIndex();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
onUpdated(() => getIndex());
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
computedIndex
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import type { ResponsiveValue } from '../interface';
|
|
3
|
+
import type { ScreenMap } from '../utils/responsive-observe';
|
|
4
|
+
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
|
5
|
+
import { isObject } from '../utils/is';
|
|
6
|
+
import ResponsiveObserve, {
|
|
7
|
+
responsiveArray
|
|
8
|
+
} from '../utils/responsive-observe';
|
|
9
|
+
|
|
10
|
+
function isResponsiveValue(
|
|
11
|
+
val: number | ResponsiveValue
|
|
12
|
+
): val is ResponsiveValue {
|
|
13
|
+
return isObject(val);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useResponsiveState(
|
|
17
|
+
val: Ref<number | ResponsiveValue>,
|
|
18
|
+
defaultVal: number,
|
|
19
|
+
fallbackToXs = false
|
|
20
|
+
) {
|
|
21
|
+
const screens = ref<ScreenMap>({
|
|
22
|
+
xs: true,
|
|
23
|
+
sm: true,
|
|
24
|
+
md: true,
|
|
25
|
+
lg: true,
|
|
26
|
+
xl: true,
|
|
27
|
+
xxl: true
|
|
28
|
+
});
|
|
29
|
+
const result = computed(() => {
|
|
30
|
+
let res = defaultVal;
|
|
31
|
+
if (isResponsiveValue(val.value)) {
|
|
32
|
+
for (let i = 0; i < responsiveArray.length; i++) {
|
|
33
|
+
const breakpoint = responsiveArray[i];
|
|
34
|
+
if (
|
|
35
|
+
(screens.value[breakpoint] ||
|
|
36
|
+
(breakpoint === 'xs' && fallbackToXs)) &&
|
|
37
|
+
val.value[breakpoint] !== undefined
|
|
38
|
+
) {
|
|
39
|
+
res = val.value[breakpoint] as number;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
res = val.value;
|
|
45
|
+
}
|
|
46
|
+
return res;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
let subscribeToken = '';
|
|
50
|
+
|
|
51
|
+
onMounted(() => {
|
|
52
|
+
subscribeToken = ResponsiveObserve.subscribe(screensVal => {
|
|
53
|
+
if (isResponsiveValue(val.value)) {
|
|
54
|
+
screens.value = screensVal;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
onUnmounted(() => {
|
|
60
|
+
if (subscribeToken) {
|
|
61
|
+
ResponsiveObserve.unsubscribe(subscribeToken);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import type { ResponsiveValue } from '../interface';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import { isNumber, isObject } from '../utils/is';
|
|
5
|
+
import { responsiveArray } from '../utils/responsive-observe';
|
|
6
|
+
|
|
7
|
+
export function useResponsiveValue(
|
|
8
|
+
props: Ref<{
|
|
9
|
+
val: number;
|
|
10
|
+
key: string;
|
|
11
|
+
xs?: number | { [key: string]: any };
|
|
12
|
+
sm?: number | { [key: string]: any };
|
|
13
|
+
md?: number | { [key: string]: any };
|
|
14
|
+
lg?: number | { [key: string]: any };
|
|
15
|
+
xl?: number | { [key: string]: any };
|
|
16
|
+
xxl?: number | { [key: string]: any };
|
|
17
|
+
}>
|
|
18
|
+
) {
|
|
19
|
+
const value = computed(() => {
|
|
20
|
+
const { val, key, xs, sm, md, lg, xl, xxl } = props.value;
|
|
21
|
+
if (!xs && !sm && !md && !lg && !xl && !xxl) {
|
|
22
|
+
return val;
|
|
23
|
+
}
|
|
24
|
+
const result: ResponsiveValue = {};
|
|
25
|
+
responsiveArray.forEach(breakpoint => {
|
|
26
|
+
const config = props.value[breakpoint];
|
|
27
|
+
if (isNumber(config)) {
|
|
28
|
+
result[breakpoint] = config;
|
|
29
|
+
} else if (isObject(config) && isNumber(config[key])) {
|
|
30
|
+
result[breakpoint] = config[key];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
});
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export interface ResponsiveValue {
|
|
2
|
+
/**
|
|
3
|
+
* @zh >= 1600px 响应式配置
|
|
4
|
+
* @en >= 1600px responsive configuration
|
|
5
|
+
*/
|
|
6
|
+
xxl?: number;
|
|
7
|
+
/**
|
|
8
|
+
* @zh >= 1200px 响应式配置
|
|
9
|
+
* @en >= 1200px responsive configuration
|
|
10
|
+
*/
|
|
11
|
+
xl?: number;
|
|
12
|
+
/**
|
|
13
|
+
* @zh >= 992px 响应式配置
|
|
14
|
+
* @en >= 992px responsive configuration
|
|
15
|
+
*/
|
|
16
|
+
lg?: number;
|
|
17
|
+
/**
|
|
18
|
+
* @zh >= 768px 响应式配置
|
|
19
|
+
* @en >= 768px responsive configuration
|
|
20
|
+
*/
|
|
21
|
+
md?: number;
|
|
22
|
+
/**
|
|
23
|
+
* @zh >= 576px 响应式配置
|
|
24
|
+
* @en >= 576px responsive configuration
|
|
25
|
+
*/
|
|
26
|
+
sm?: number;
|
|
27
|
+
/**
|
|
28
|
+
* @zh < 576px 响应式配置
|
|
29
|
+
* @en <576px responsive configuration
|
|
30
|
+
*/
|
|
31
|
+
xs?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type FlexType = number | string | 'initial' | 'auto' | 'none';
|
|
35
|
+
|
|
36
|
+
export interface RowProps {
|
|
37
|
+
gutter?: number | ResponsiveValue | ResponsiveValue[];
|
|
38
|
+
justify?: 'start' | 'center' | 'end' | 'space-around' | 'space-between';
|
|
39
|
+
align?: 'start' | 'center' | 'end' | 'stretch';
|
|
40
|
+
div?: boolean;
|
|
41
|
+
wrap?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ColProps {
|
|
45
|
+
span?: number;
|
|
46
|
+
offset?: number | undefined;
|
|
47
|
+
order?: number | undefined;
|
|
48
|
+
xs?: number | { [key: string]: any } | undefined;
|
|
49
|
+
sm?: number | { [key: string]: any } | undefined;
|
|
50
|
+
md?: number | { [key: string]: any } | undefined;
|
|
51
|
+
lg?: number | { [key: string]: any } | undefined;
|
|
52
|
+
xl?: number | { [key: string]: any } | undefined;
|
|
53
|
+
xxl?: number | { [key: string]: any } | undefined;
|
|
54
|
+
flex?: number | string | 'initial' | 'auto' | 'none' | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface GridProps {
|
|
58
|
+
cols?: number | ResponsiveValue;
|
|
59
|
+
rowGap?: number | ResponsiveValue;
|
|
60
|
+
colGap?: number | ResponsiveValue;
|
|
61
|
+
collapsed?: boolean;
|
|
62
|
+
collapsedRows?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface GridItemProps {
|
|
66
|
+
span?: number | ResponsiveValue;
|
|
67
|
+
offset?: number | ResponsiveValue;
|
|
68
|
+
suffix?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface GridItemData extends GridItemProps {
|
|
72
|
+
span: number;
|
|
73
|
+
offset: number;
|
|
74
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { GridItemData } from '../interface';
|
|
2
|
+
|
|
3
|
+
export function resolveItemData(
|
|
4
|
+
cols: number,
|
|
5
|
+
props: GridItemData
|
|
6
|
+
): GridItemData {
|
|
7
|
+
const originSpan = props.span ?? 1;
|
|
8
|
+
const originOffset = props.offset ?? 0;
|
|
9
|
+
const offset = Math.min(originOffset, cols);
|
|
10
|
+
const span = Math.min(
|
|
11
|
+
offset > 0 ? originSpan + originOffset : originSpan,
|
|
12
|
+
cols
|
|
13
|
+
);
|
|
14
|
+
return {
|
|
15
|
+
span,
|
|
16
|
+
offset,
|
|
17
|
+
suffix: 'suffix' in props ? props.suffix !== false : false
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function setItemVisible({
|
|
22
|
+
cols,
|
|
23
|
+
collapsed,
|
|
24
|
+
collapsedRows,
|
|
25
|
+
itemDataList
|
|
26
|
+
}: {
|
|
27
|
+
cols: number;
|
|
28
|
+
collapsed: boolean;
|
|
29
|
+
collapsedRows: number;
|
|
30
|
+
itemDataList: GridItemData[];
|
|
31
|
+
}) {
|
|
32
|
+
let overflow = false;
|
|
33
|
+
let displayIndexList: number[] = [];
|
|
34
|
+
|
|
35
|
+
function isOverflow(span: number) {
|
|
36
|
+
return Math.ceil(span / cols) > collapsedRows;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (collapsed) {
|
|
40
|
+
let spanSum = 0;
|
|
41
|
+
for (let i = 0; i < itemDataList.length; i++) {
|
|
42
|
+
if (itemDataList[i].suffix) {
|
|
43
|
+
spanSum += itemDataList[i].span;
|
|
44
|
+
displayIndexList.push(i);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!isOverflow(spanSum)) {
|
|
48
|
+
let current = 0;
|
|
49
|
+
while (current < itemDataList.length) {
|
|
50
|
+
const item = itemDataList[current];
|
|
51
|
+
if (!item.suffix) {
|
|
52
|
+
spanSum += item.span;
|
|
53
|
+
|
|
54
|
+
if (isOverflow(spanSum)) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
displayIndexList.push(current);
|
|
58
|
+
}
|
|
59
|
+
current++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
overflow = itemDataList.some(
|
|
63
|
+
(item, index) => !item.suffix && !displayIndexList.includes(index)
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
displayIndexList = itemDataList.map((_, index) => index);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
overflow,
|
|
71
|
+
displayIndexList
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const opt = Object.prototype.toString;
|
|
2
|
+
|
|
3
|
+
export function isObject(obj: unknown): obj is Record<string, any> {
|
|
4
|
+
return opt.call(obj) === '[object Object]';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isNumber(obj: any): obj is number {
|
|
8
|
+
return opt.call(obj) === '[object Number]' && obj === obj; // eslint-disable-line
|
|
9
|
+
}
|