gi-component 0.0.37 → 0.0.39
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/dist/components/descriptions/index.d.ts +4 -0
- package/dist/components/descriptions/src/descriptions.vue.d.ts +23 -0
- package/dist/components/descriptions/src/type.d.ts +20 -0
- package/dist/components/dialog/src/dialog.vue.d.ts +1 -1
- package/dist/components/table/index.d.ts +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +118 -7
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/types/tool.d.ts +1 -1
- package/package.json +1 -1
- package/packages/components/button/src/button.vue +60 -60
- package/packages/components/descriptions/index.ts +5 -0
- package/packages/components/descriptions/src/descriptions.vue +72 -0
- package/packages/components/descriptions/src/type.ts +44 -0
- package/packages/components/flex/index.ts +5 -0
- package/packages/components/flex/src/flex.vue +72 -0
- package/packages/components/flex/src/type.ts +14 -0
- package/packages/components.d.ts +2 -0
- package/packages/index.ts +7 -0
package/dist/types/tool.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
type AllKeys<T> = T extends any ? keyof T : never;
|
|
2
2
|
type UnionType<T, K extends PropertyKey> = T extends any ? K extends keyof T ? T[K] : never : never;
|
|
3
3
|
export type MergeMultiple<T extends any[]> = {
|
|
4
|
-
[K in AllKeys<T[number]>]
|
|
4
|
+
[K in AllKeys<T[number]>]?: UnionType<T[number], K>;
|
|
5
5
|
};
|
|
6
6
|
export {};
|
package/package.json
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<ElButton :class="b('button')" v-bind="bindProps" @click="(e: MouseEvent) => emit('click', e)">
|
|
3
|
-
<slot>{{ btnText }}</slot>
|
|
4
|
-
</ElButton>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import type { ButtonProps as ElButtonProps } from 'element-plus'
|
|
9
|
-
import type { ButtonProps } from './type.ts'
|
|
10
|
-
import {
|
|
11
|
-
Delete,
|
|
12
|
-
Download,
|
|
13
|
-
Edit,
|
|
14
|
-
Plus,
|
|
15
|
-
Printer,
|
|
16
|
-
Search,
|
|
17
|
-
Upload
|
|
18
|
-
} from '@element-plus/icons-vue'
|
|
19
|
-
import { ElButton } from 'element-plus'
|
|
20
|
-
import { computed, useAttrs } from 'vue'
|
|
21
|
-
import { useBemClass } from '../../../hooks'
|
|
22
|
-
|
|
23
|
-
const props = withDefaults(defineProps<ButtonProps>(), {
|
|
24
|
-
type: ''
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
const emit = defineEmits<{
|
|
28
|
-
(e: 'click', event: MouseEvent): void
|
|
29
|
-
}>()
|
|
30
|
-
|
|
31
|
-
const attrs = useAttrs()
|
|
32
|
-
|
|
33
|
-
const { b } = useBemClass()
|
|
34
|
-
|
|
35
|
-
const obj: Record<string, { btnProps: Partial<ButtonProps>, btnText: string }>
|
|
36
|
-
= {
|
|
37
|
-
add: { btnProps: { icon: Plus, type: 'primary' }, btnText: '新增' },
|
|
38
|
-
edit: { btnProps: { icon: Edit, type: 'primary' }, btnText: '编辑' },
|
|
39
|
-
delete: { btnProps: { icon: Delete, type: 'danger' }, btnText: '删除' },
|
|
40
|
-
search: { btnProps: { icon: Search, type: 'primary' }, btnText: '搜索' },
|
|
41
|
-
reset: { btnProps: { type: undefined }, btnText: '重置' },
|
|
42
|
-
upload: { btnProps: { icon: Upload }, btnText: '上传' },
|
|
43
|
-
download: {
|
|
44
|
-
btnProps: { icon: Download },
|
|
45
|
-
btnText: '下载'
|
|
46
|
-
},
|
|
47
|
-
print: { btnProps: { icon: Printer }, btnText: '打印' }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const bindProps = computed(() => {
|
|
51
|
-
const btnProps = obj?.[props.type]?.btnProps || { type: props.type }
|
|
52
|
-
return { ...attrs, ...props, ...btnProps } as Omit<ElButtonProps, 'type'>
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const btnText = computed(() => {
|
|
56
|
-
return obj[props.type].btnText
|
|
57
|
-
})
|
|
58
|
-
</script>
|
|
59
|
-
|
|
60
|
-
<style lang="scss" scoped></style>
|
|
1
|
+
<template>
|
|
2
|
+
<ElButton :class="b('button')" v-bind="bindProps" @click="(e: MouseEvent) => emit('click', e)">
|
|
3
|
+
<slot>{{ btnText }}</slot>
|
|
4
|
+
</ElButton>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import type { ButtonProps as ElButtonProps } from 'element-plus'
|
|
9
|
+
import type { ButtonProps } from './type.ts'
|
|
10
|
+
import {
|
|
11
|
+
Delete,
|
|
12
|
+
Download,
|
|
13
|
+
Edit,
|
|
14
|
+
Plus,
|
|
15
|
+
Printer,
|
|
16
|
+
Search,
|
|
17
|
+
Upload
|
|
18
|
+
} from '@element-plus/icons-vue'
|
|
19
|
+
import { ElButton } from 'element-plus'
|
|
20
|
+
import { computed, useAttrs } from 'vue'
|
|
21
|
+
import { useBemClass } from '../../../hooks'
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<ButtonProps>(), {
|
|
24
|
+
type: ''
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const emit = defineEmits<{
|
|
28
|
+
(e: 'click', event: MouseEvent): void
|
|
29
|
+
}>()
|
|
30
|
+
|
|
31
|
+
const attrs = useAttrs()
|
|
32
|
+
|
|
33
|
+
const { b } = useBemClass()
|
|
34
|
+
|
|
35
|
+
const obj: Record<string, { btnProps: Partial<ButtonProps>, btnText: string }>
|
|
36
|
+
= {
|
|
37
|
+
add: { btnProps: { icon: Plus, type: 'primary' }, btnText: '新增' },
|
|
38
|
+
edit: { btnProps: { icon: Edit, type: 'primary' }, btnText: '编辑' },
|
|
39
|
+
delete: { btnProps: { icon: Delete, type: 'danger' }, btnText: '删除' },
|
|
40
|
+
search: { btnProps: { icon: Search, type: 'primary' }, btnText: '搜索' },
|
|
41
|
+
reset: { btnProps: { type: undefined }, btnText: '重置' },
|
|
42
|
+
upload: { btnProps: { icon: Upload }, btnText: '上传' },
|
|
43
|
+
download: {
|
|
44
|
+
btnProps: { icon: Download },
|
|
45
|
+
btnText: '下载'
|
|
46
|
+
},
|
|
47
|
+
print: { btnProps: { icon: Printer }, btnText: '打印' }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const bindProps = computed(() => {
|
|
51
|
+
const btnProps = obj?.[props.type]?.btnProps || { type: props.type }
|
|
52
|
+
return { ...attrs, ...props, ...btnProps } as Omit<ElButtonProps, 'type'>
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const btnText = computed(() => {
|
|
56
|
+
return obj[props.type].btnText
|
|
57
|
+
})
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ElDescriptions :border="border" :column="column" :direction="direction" :size="size" :title="title" :extra="extra">
|
|
3
|
+
<template v-if="$slots.title" #title>
|
|
4
|
+
<slot name="title" />
|
|
5
|
+
</template>
|
|
6
|
+
<template v-if="$slots.extra" #extra>
|
|
7
|
+
<slot name="extra" />
|
|
8
|
+
</template>
|
|
9
|
+
<template v-if="useColumns">
|
|
10
|
+
<ElDescriptionsItem v-for="(col, idx) in columns" :key="col.value ?? idx"
|
|
11
|
+
:label="typeof col.label === 'string' ? col.label : ''" :span="col.span ?? 1" :width="col.width"
|
|
12
|
+
:min-width="col.minWidth" :align="col.align ?? 'left'" :label-align="col.labelAlign" :class-name="col.className"
|
|
13
|
+
:label-class-name="col.labelClassName">
|
|
14
|
+
<template v-if="typeof col.label === 'function'" #label>
|
|
15
|
+
<NodeRenderer :get-node="() => (col.label as (c: DescriptionsColumnItem) => any)(col)" />
|
|
16
|
+
</template>
|
|
17
|
+
<slot v-if="hasColumnSlot(col.value)" :name="col.value" :value="getFieldValue(col)" :data="data" :column="col" />
|
|
18
|
+
<NodeRenderer v-else-if="col.render && data" :get-node="() => col.render!({ value: getFieldValue(col), data, column: col })" />
|
|
19
|
+
<span v-else>{{ getFieldValue(col) }}</span>
|
|
20
|
+
</ElDescriptionsItem>
|
|
21
|
+
</template>
|
|
22
|
+
<template v-else>
|
|
23
|
+
<slot />
|
|
24
|
+
</template>
|
|
25
|
+
</ElDescriptions>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
import type { DescriptionsColumnItem, DescriptionsProps } from './type'
|
|
30
|
+
import { ElDescriptions, ElDescriptionsItem } from 'element-plus'
|
|
31
|
+
import { computed, defineComponent, useSlots } from 'vue'
|
|
32
|
+
|
|
33
|
+
const props = withDefaults(defineProps<DescriptionsProps>(), {
|
|
34
|
+
columns: () => [],
|
|
35
|
+
data: () => ({}),
|
|
36
|
+
border: false,
|
|
37
|
+
column: 3,
|
|
38
|
+
direction: 'horizontal',
|
|
39
|
+
size: 'default',
|
|
40
|
+
title: '',
|
|
41
|
+
extra: ''
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
defineSlots<{
|
|
45
|
+
default?: () => any
|
|
46
|
+
title?: () => any
|
|
47
|
+
extra?: () => any
|
|
48
|
+
}>()
|
|
49
|
+
|
|
50
|
+
const NodeRenderer = defineComponent({
|
|
51
|
+
name: 'NodeRenderer',
|
|
52
|
+
props: {
|
|
53
|
+
getNode: { type: Function, required: true }
|
|
54
|
+
},
|
|
55
|
+
setup(props: { getNode: () => any }) {
|
|
56
|
+
return () => props.getNode()
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const slots = useSlots()
|
|
61
|
+
const useColumns = computed(() => (props.columns?.length ?? 0) > 0)
|
|
62
|
+
|
|
63
|
+
function hasColumnSlot(name: string | undefined): boolean {
|
|
64
|
+
return !!name && !!(slots as Record<string, unknown>)[name]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getFieldValue(col: DescriptionsColumnItem) {
|
|
68
|
+
if (!props.data || col.value === undefined || col.value === null)
|
|
69
|
+
return ''
|
|
70
|
+
return props.data[col.value]
|
|
71
|
+
}
|
|
72
|
+
</script>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { VNode } from 'vue'
|
|
2
|
+
|
|
3
|
+
/** 描述列表列配置(对应 data 的字段与展示) */
|
|
4
|
+
export interface DescriptionsColumnItem {
|
|
5
|
+
/** 对应 data 的字段名 */
|
|
6
|
+
value?: string
|
|
7
|
+
/** 标签文本,或返回 VNode 的函数 */
|
|
8
|
+
label?: string | ((columnItem: DescriptionsColumnItem) => VNode)
|
|
9
|
+
/** 列的数量(占据几列) */
|
|
10
|
+
span?: number
|
|
11
|
+
/** 列宽度(如无 border,宽度包含标签与内容) */
|
|
12
|
+
width?: string | number
|
|
13
|
+
/** 列最小宽度,剩余宽度按比例分配给设置了 minWidth 的列 */
|
|
14
|
+
minWidth?: string | number
|
|
15
|
+
/** 列内容对齐方式 */
|
|
16
|
+
align?: 'left' | 'center' | 'right'
|
|
17
|
+
/** 列标签对齐方式(无 border 时用 align) */
|
|
18
|
+
labelAlign?: 'left' | 'center' | 'right'
|
|
19
|
+
/** 列内容自定义类名 */
|
|
20
|
+
className?: string
|
|
21
|
+
/** 列标签自定义类名 */
|
|
22
|
+
labelClassName?: string
|
|
23
|
+
/** 自定义渲染内容:({ value, data, column }) => VNode */
|
|
24
|
+
render?: (params: { value: any; data: Record<string, any>; column: DescriptionsColumnItem }) => VNode
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DescriptionsProps {
|
|
28
|
+
/** 描述列表配置项,与 data 配合使用 */
|
|
29
|
+
columns?: DescriptionsColumnItem[]
|
|
30
|
+
/** 详情数据(与 columns 配合,按 value 取字段) */
|
|
31
|
+
data?: Record<string, any>
|
|
32
|
+
/** 是否带边框 */
|
|
33
|
+
border?: boolean
|
|
34
|
+
/** 一行 Descriptions Item 的数量 */
|
|
35
|
+
column?: number
|
|
36
|
+
/** 排列方向 */
|
|
37
|
+
direction?: 'vertical' | 'horizontal'
|
|
38
|
+
/** 列表尺寸 */
|
|
39
|
+
size?: 'large' | 'default' | 'small'
|
|
40
|
+
/** 标题文本,显示在左上方,也可用 title 插槽 */
|
|
41
|
+
title?: string
|
|
42
|
+
/** 操作区,显示在右上方,也可用 extra 插槽 */
|
|
43
|
+
extra?: string
|
|
44
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="classNames" :style="style">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import type { CSSProperties } from 'vue'
|
|
9
|
+
import type { FlexProps } from './type'
|
|
10
|
+
import { computed } from 'vue'
|
|
11
|
+
import { useBemClass } from '../../../hooks'
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<FlexProps>(), {
|
|
14
|
+
vertical: false,
|
|
15
|
+
wrap: false,
|
|
16
|
+
justify: 'normal',
|
|
17
|
+
align: 'normal',
|
|
18
|
+
flex: 'normal'
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const { b } = useBemClass()
|
|
22
|
+
|
|
23
|
+
const classNames = computed(() => [b('flex')])
|
|
24
|
+
|
|
25
|
+
const gapMap: Record<string, string> = {
|
|
26
|
+
small: '8px',
|
|
27
|
+
middle: '16px',
|
|
28
|
+
large: '24px'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const resolvedGap = computed(() => {
|
|
32
|
+
if (props.gap === undefined || props.gap === null || props.gap === '')
|
|
33
|
+
return undefined
|
|
34
|
+
if (typeof props.gap === 'number')
|
|
35
|
+
return `${props.gap}px`
|
|
36
|
+
if (gapMap[props.gap])
|
|
37
|
+
return gapMap[props.gap]
|
|
38
|
+
return String(props.gap)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const resolvedWrap = computed(() => {
|
|
42
|
+
if (typeof props.wrap === 'boolean')
|
|
43
|
+
return props.wrap ? 'wrap' : 'nowrap'
|
|
44
|
+
// 模板中写 wrap 无值时 Vue 传空字符串,视为开启换行
|
|
45
|
+
if (props.wrap === '')
|
|
46
|
+
return 'wrap'
|
|
47
|
+
return props.wrap
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const style = computed<CSSProperties>(() => {
|
|
51
|
+
const obj: CSSProperties = {
|
|
52
|
+
display: 'flex',
|
|
53
|
+
flexDirection: props.vertical ? 'column' : 'row',
|
|
54
|
+
flexWrap: resolvedWrap.value,
|
|
55
|
+
justifyContent: props.justify,
|
|
56
|
+
alignItems: props.align
|
|
57
|
+
}
|
|
58
|
+
if (props.flex !== 'normal') {
|
|
59
|
+
obj.flex = props.flex
|
|
60
|
+
}
|
|
61
|
+
if (resolvedGap.value) {
|
|
62
|
+
obj.gap = resolvedGap.value
|
|
63
|
+
}
|
|
64
|
+
return obj
|
|
65
|
+
})
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<style scoped lang="scss">
|
|
69
|
+
:deep(.el-button+.el-button) {
|
|
70
|
+
margin-left: 0;
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface FlexProps {
|
|
2
|
+
/** Flex 主轴的方向是否垂直,使用 flex-direction: column */
|
|
3
|
+
vertical?: boolean
|
|
4
|
+
/** 设置元素单行显示还是多行显示,参考 flex-wrap;支持布尔值,true 为 wrap,false 为 nowrap */
|
|
5
|
+
wrap?: 'nowrap' | 'wrap' | 'wrap-reverse' | boolean | ''
|
|
6
|
+
/** 设置元素在主轴方向上的对齐方式,参考 justify-content */
|
|
7
|
+
justify?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'
|
|
8
|
+
/** 设置元素在交叉轴方向上的对齐方式,参考 align-items */
|
|
9
|
+
align?: 'normal' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'
|
|
10
|
+
/** flex CSS 简写属性 */
|
|
11
|
+
flex?: string
|
|
12
|
+
/** 设置网格之间的间隙,可选预设 small / middle / large 或 string / number */
|
|
13
|
+
gap?: 'small' | 'middle' | 'large' | string | number
|
|
14
|
+
}
|
package/packages/components.d.ts
CHANGED
|
@@ -12,9 +12,11 @@ declare module 'vue' {
|
|
|
12
12
|
GiCard: typeof import('./components/card/src/card.vue')['default']
|
|
13
13
|
GiDialog: typeof import('./components/dialog/src/dialog.vue')['default']
|
|
14
14
|
GiDialogContent: typeof import('./components/dialog/src/dialog-content.vue')['default']
|
|
15
|
+
GiDescriptions: typeof import('./components/descriptions/src/descriptions.vue')['default']
|
|
15
16
|
GiDot: typeof import('./components/dot/src/dot.vue')['default']
|
|
16
17
|
GiDrawer: typeof import('./components/drawer/src/drawer.vue')['default']
|
|
17
18
|
GiEditTable: typeof import('./components/edit-table/src/edit-table.vue')['default']
|
|
19
|
+
GiFlex: typeof import('./components/flex/src/flex.vue')['default']
|
|
18
20
|
GiForm: typeof import('./components/form/src/form.vue')['default']
|
|
19
21
|
GiGrid: typeof import('./components/grid/src/grid.vue')['default']
|
|
20
22
|
GiGridItem: typeof import('./components/grid/src/grid-item.vue')['default']
|
package/packages/index.ts
CHANGED
|
@@ -2,10 +2,12 @@ import type { App, Component } from 'vue'
|
|
|
2
2
|
|
|
3
3
|
import Button from './components/button'
|
|
4
4
|
import Card from './components/card'
|
|
5
|
+
import Descriptions from './components/descriptions'
|
|
5
6
|
import DialogComponent, { Dialog as DialogFunction } from './components/dialog'
|
|
6
7
|
import Dot from './components/dot'
|
|
7
8
|
import Drawer from './components/drawer'
|
|
8
9
|
import EditTable from './components/edit-table'
|
|
10
|
+
import Flex from './components/flex'
|
|
9
11
|
import Form from './components/form'
|
|
10
12
|
import GridItem from './components/grid/src/grid-item.vue'
|
|
11
13
|
import Grid from './components/grid/src/grid.vue'
|
|
@@ -20,6 +22,7 @@ import './styles/index.scss'
|
|
|
20
22
|
// 防止打包时 tree-shake 掉 Dialog.info/success/warning/error(内部只用到 Dialog.open)
|
|
21
23
|
void [DialogFunction.info, DialogFunction.success, DialogFunction.warning, DialogFunction.error]
|
|
22
24
|
|
|
25
|
+
export * from './components/descriptions'
|
|
23
26
|
export * from './components/dialog'
|
|
24
27
|
export * from './components/drawer'
|
|
25
28
|
export * from './components/edit-table'
|
|
@@ -32,11 +35,13 @@ export * from './utils'
|
|
|
32
35
|
const components = {
|
|
33
36
|
Button,
|
|
34
37
|
Card,
|
|
38
|
+
Descriptions,
|
|
35
39
|
Drawer,
|
|
36
40
|
Dot,
|
|
37
41
|
Tabs,
|
|
38
42
|
InputGroup,
|
|
39
43
|
InputSearch,
|
|
44
|
+
Flex,
|
|
40
45
|
Grid,
|
|
41
46
|
GridItem,
|
|
42
47
|
Form,
|
|
@@ -50,11 +55,13 @@ const components = {
|
|
|
50
55
|
// 导出Gi前缀的组件并添加明确类型注解
|
|
51
56
|
export const GiButton: typeof Button = Button
|
|
52
57
|
export const GiCard: typeof Card = Card
|
|
58
|
+
export const GiDescriptions: typeof Descriptions = Descriptions
|
|
53
59
|
export const GiDrawer: typeof Drawer = Drawer
|
|
54
60
|
export const GiDot: typeof Dot = Dot
|
|
55
61
|
export const GiTabs: typeof Tabs = Tabs
|
|
56
62
|
export const GiInputGroup: typeof InputGroup = InputGroup
|
|
57
63
|
export const GiInputSearch: typeof InputSearch = InputSearch
|
|
64
|
+
export const GiFlex: typeof Flex = Flex
|
|
58
65
|
export const GiGrid: typeof Grid = Grid
|
|
59
66
|
export const GiGridItem: typeof GridItem = GridItem
|
|
60
67
|
export const GiForm: typeof Form = Form
|