mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
refactor(components): [descriptions] switch to script-setup syntax (#8349)
This commit is contained in:
@@ -3,7 +3,7 @@ import { nextTick, ref } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import ElTag from '@element-plus/components/tag'
|
||||
import ElDescriptions from '../src/index.vue'
|
||||
import ElDescriptions from '../src/description.vue'
|
||||
import ElDescriptionsItem from '../src/description-item'
|
||||
|
||||
describe('Descriptions.vue', () => {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { withInstall, withNoopInstall } from '@element-plus/utils'
|
||||
|
||||
import Descriptions from './src/index.vue'
|
||||
import Descriptions from './src/description.vue'
|
||||
import DescriptionsItem from './src/description-item'
|
||||
|
||||
export const ElDescriptions = withInstall(Descriptions, {
|
||||
DescriptionsItem,
|
||||
})
|
||||
export default ElDescriptions
|
||||
|
||||
export const ElDescriptionsItem = withNoopInstall(DescriptionsItem)
|
||||
|
||||
export default ElDescriptions
|
||||
|
||||
export * from './src/description'
|
||||
|
||||
31
packages/components/descriptions/src/description.ts
Normal file
31
packages/components/descriptions/src/description.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
import { useSizeProp } from '@element-plus/hooks'
|
||||
|
||||
import type Description from './description.vue'
|
||||
|
||||
export const descriptionProps = buildProps({
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
column: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
direction: {
|
||||
type: String,
|
||||
values: ['horizontal', 'vertical'],
|
||||
default: 'horizontal',
|
||||
},
|
||||
size: useSizeProp,
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
extra: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
} as const)
|
||||
|
||||
export type DescriptionInstance = InstanceType<typeof Description>
|
||||
115
packages/components/descriptions/src/description.vue
Normal file
115
packages/components/descriptions/src/description.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div :class="descriptionKls">
|
||||
<div
|
||||
v-if="title || extra || $slots.title || $slots.extra"
|
||||
:class="ns.e('header')"
|
||||
>
|
||||
<div :class="ns.e('title')">
|
||||
<slot name="title">{{ title }}</slot>
|
||||
</div>
|
||||
<div :class="ns.e('extra')">
|
||||
<slot name="extra">{{ extra }}</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="ns.e('body')">
|
||||
<table :class="[ns.e('table'), ns.is('bordered', border)]">
|
||||
<tbody>
|
||||
<template v-for="(row, index) in getRows()" :key="index">
|
||||
<el-descriptions-row :row="row" />
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// @ts-nocheck
|
||||
import { computed, provide, useSlots } from 'vue'
|
||||
import { useNamespace, useSize } from '@element-plus/hooks'
|
||||
import ElDescriptionsRow from './descriptions-row.vue'
|
||||
import { descriptionsKey } from './token'
|
||||
import { descriptionProps } from './description'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElDescriptions',
|
||||
})
|
||||
|
||||
const props = defineProps(descriptionProps)
|
||||
|
||||
const ns = useNamespace('descriptions')
|
||||
|
||||
const descriptionsSize = useSize()
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
provide(descriptionsKey, props)
|
||||
|
||||
const descriptionKls = computed(() => [ns.b(), ns.m(descriptionsSize.value)])
|
||||
|
||||
const flattedChildren = (children) => {
|
||||
const temp = Array.isArray(children) ? children : [children]
|
||||
const res = []
|
||||
temp.forEach((child) => {
|
||||
if (Array.isArray(child.children)) {
|
||||
res.push(...flattedChildren(child.children))
|
||||
} else {
|
||||
res.push(child)
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
const filledNode = (node, span, count, isLast = false) => {
|
||||
if (!node.props) {
|
||||
node.props = {}
|
||||
}
|
||||
if (span > count) {
|
||||
node.props.span = count
|
||||
}
|
||||
if (isLast) {
|
||||
// set the last span
|
||||
node.props.span = span
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
const getRows = () => {
|
||||
const children = flattedChildren(slots.default?.()).filter(
|
||||
(node) => node?.type?.name === 'ElDescriptionsItem'
|
||||
)
|
||||
const rows = []
|
||||
let temp = []
|
||||
let count = props.column
|
||||
let totalSpan = 0 // all spans number of item
|
||||
|
||||
children.forEach((node, index) => {
|
||||
const span = node.props?.span || 1
|
||||
|
||||
if (index < children.length - 1) {
|
||||
totalSpan += span > count ? count : span
|
||||
}
|
||||
|
||||
if (index === children.length - 1) {
|
||||
// calculate the last item span
|
||||
const lastSpan = props.column - (totalSpan % props.column)
|
||||
temp.push(filledNode(node, lastSpan, count, true))
|
||||
rows.push(temp)
|
||||
return
|
||||
}
|
||||
|
||||
if (span < count) {
|
||||
count -= span
|
||||
temp.push(node)
|
||||
} else {
|
||||
temp.push(filledNode(node, span, count))
|
||||
rows.push(temp)
|
||||
count = props.column
|
||||
temp = []
|
||||
}
|
||||
})
|
||||
|
||||
return rows
|
||||
}
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
import { defineComponent, h, inject } from 'vue'
|
||||
import { addUnit, getNormalizedProps } from '@element-plus/utils'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { elDescriptionsKey } from './token'
|
||||
import { descriptionsKey } from './token'
|
||||
|
||||
import type { VNode } from 'vue'
|
||||
import type {
|
||||
@@ -24,7 +24,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const descriptions = inject(elDescriptionsKey, {} as IDescriptionsInject)
|
||||
const descriptions = inject(descriptionsKey, {} as IDescriptionsInject)
|
||||
|
||||
return {
|
||||
descriptions,
|
||||
|
||||
8
packages/components/descriptions/src/descriptions-row.ts
Normal file
8
packages/components/descriptions/src/descriptions-row.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
|
||||
export const descriptionsRowProps = buildProps({
|
||||
row: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
} as const)
|
||||
@@ -22,30 +22,21 @@
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
// @ts-nocheck
|
||||
import { defineComponent, inject } from 'vue'
|
||||
import DescriptionsCell from './descriptions-cell'
|
||||
import { elDescriptionsKey } from './token'
|
||||
import { inject } from 'vue'
|
||||
|
||||
import ElDescriptionsCell from './descriptions-cell'
|
||||
import { descriptionsKey } from './token'
|
||||
import { descriptionsRowProps } from './descriptions-row'
|
||||
|
||||
import type { IDescriptionsInject } from './descriptions.type'
|
||||
|
||||
export default defineComponent({
|
||||
defineOptions({
|
||||
name: 'ElDescriptionsRow',
|
||||
components: {
|
||||
[DescriptionsCell.name]: DescriptionsCell,
|
||||
},
|
||||
props: {
|
||||
row: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const descriptions = inject(elDescriptionsKey, {} as IDescriptionsInject)
|
||||
|
||||
return {
|
||||
descriptions,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
defineProps(descriptionsRowProps)
|
||||
|
||||
const descriptions = inject(descriptionsKey, {} as IDescriptionsInject)
|
||||
</script>
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
<template>
|
||||
<div :class="descriptionKls">
|
||||
<div
|
||||
v-if="title || extra || $slots.title || $slots.extra"
|
||||
:class="ns.e('header')"
|
||||
>
|
||||
<div :class="ns.e('title')">
|
||||
<slot name="title">{{ title }}</slot>
|
||||
</div>
|
||||
<div :class="ns.e('extra')">
|
||||
<slot name="extra">{{ extra }}</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="ns.e('body')">
|
||||
<table :class="[ns.e('table'), ns.is('bordered', border)]">
|
||||
<tbody>
|
||||
<template v-for="(row, index) in getRows()" :key="index">
|
||||
<el-descriptions-row :row="row" />
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { computed, defineComponent, provide } from 'vue'
|
||||
import { isValidComponentSize } from '@element-plus/utils'
|
||||
import { useNamespace, useSize } from '@element-plus/hooks'
|
||||
import DescriptionsRow from './descriptions-row.vue'
|
||||
import { elDescriptionsKey } from './token'
|
||||
|
||||
import type { PropType } from 'vue'
|
||||
import type { ComponentSize } from '@element-plus/constants'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElDescriptions',
|
||||
components: {
|
||||
[DescriptionsRow.name]: DescriptionsRow,
|
||||
},
|
||||
props: {
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
column: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
direction: {
|
||||
type: String as PropType<'horizontal' | 'vertical'>,
|
||||
default: 'horizontal',
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<ComponentSize>,
|
||||
validator: isValidComponentSize,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
extra: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
provide(elDescriptionsKey, props)
|
||||
|
||||
const descriptionsSize = useSize()
|
||||
const ns = useNamespace('descriptions')
|
||||
|
||||
const descriptionKls = computed(() => [
|
||||
ns.b(),
|
||||
ns.m(descriptionsSize.value),
|
||||
])
|
||||
|
||||
const flattedChildren = (children) => {
|
||||
const temp = Array.isArray(children) ? children : [children]
|
||||
const res = []
|
||||
temp.forEach((child) => {
|
||||
if (Array.isArray(child.children)) {
|
||||
res.push(...flattedChildren(child.children))
|
||||
} else {
|
||||
res.push(child)
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
const filledNode = (node, span, count, isLast = false) => {
|
||||
if (!node.props) {
|
||||
node.props = {}
|
||||
}
|
||||
if (span > count) {
|
||||
node.props.span = count
|
||||
}
|
||||
if (isLast) {
|
||||
// set the last span
|
||||
node.props.span = span
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
const getRows = () => {
|
||||
const children = flattedChildren(slots.default?.()).filter(
|
||||
(node) => node?.type?.name === 'ElDescriptionsItem'
|
||||
)
|
||||
const rows = []
|
||||
let temp = []
|
||||
let count = props.column
|
||||
let totalSpan = 0 // all spans number of item
|
||||
|
||||
children.forEach((node, index) => {
|
||||
const span = node.props?.span || 1
|
||||
|
||||
if (index < children.length - 1) {
|
||||
totalSpan += span > count ? count : span
|
||||
}
|
||||
|
||||
if (index === children.length - 1) {
|
||||
// calculate the last item span
|
||||
const lastSpan = props.column - (totalSpan % props.column)
|
||||
temp.push(filledNode(node, lastSpan, count, true))
|
||||
rows.push(temp)
|
||||
return
|
||||
}
|
||||
|
||||
if (span < count) {
|
||||
count -= span
|
||||
temp.push(node)
|
||||
} else {
|
||||
temp.push(filledNode(node, span, count))
|
||||
rows.push(temp)
|
||||
count = props.column
|
||||
temp = []
|
||||
}
|
||||
})
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
return {
|
||||
descriptionKls,
|
||||
getRows,
|
||||
ns,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { InjectionKey } from 'vue'
|
||||
import type { IDescriptionsInject } from './descriptions.type'
|
||||
|
||||
export const elDescriptionsKey =
|
||||
export const descriptionsKey =
|
||||
'elDescriptions' as any as InjectionKey<IDescriptionsInject>
|
||||
|
||||
Reference in New Issue
Block a user