forked from opentiny/tiny-vue
feat(tabs): [tabs] Add panel configuration function to adapt to the new SMB specifications (#1547)
This commit is contained in:
parent
e7ab21759b
commit
147de7fdde
|
@ -7,7 +7,7 @@ export default {
|
|||
props: [
|
||||
{
|
||||
name: 'active-color',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '当前页签的字体颜色',
|
||||
|
@ -237,7 +237,7 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'v-model',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '绑定值,选中选项卡的 name',
|
||||
|
@ -248,7 +248,7 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'v-model / modelValue',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '选中选项卡的 name',
|
||||
|
@ -284,8 +284,8 @@ export default {
|
|||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'beforeClose',
|
||||
type: 'Function',
|
||||
name: 'before-close',
|
||||
type: '(name: string)=> boolean | Promise<boolean>',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': '关闭页签前的回调函数,入参为页签名。如果函数返回false 或 拒绝的Promise,则不关闭页签',
|
||||
|
@ -296,6 +296,18 @@ export default {
|
|||
pcDemo: 'tabs-events-close',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'more-show-all',
|
||||
type: 'boolean',
|
||||
defaultValue: 'false',
|
||||
desc: {
|
||||
'zh-CN': `'更多'按钮触发的下拉面板是否展示全部页签项,适用于超大数据量的情况`,
|
||||
'en-US':
|
||||
'Indicates whether to display all tab items in the drop-down panel triggered by the More button. This parameter applies to the scenario where the data volume is large.'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'more-show-all'
|
||||
},
|
||||
{
|
||||
name: 'overflow-title',
|
||||
type: 'boolean',
|
||||
|
@ -309,9 +321,32 @@ export default {
|
|||
pcDemo: 'overflow-title',
|
||||
mfDemo: ''
|
||||
},
|
||||
{
|
||||
name: 'panel-max-height',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': `'更多'按钮触发的下拉面板最大高度,超出则显示滚动条,适用于超大数据量的情况`,
|
||||
'en-US':
|
||||
'Maximum height of the drop-down panel triggered by the More button. If the height is exceeded, a scroll bar is displayed. This applies to the scenario where the data volume is large'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'more-show-all'
|
||||
},
|
||||
{
|
||||
name: 'panel-width',
|
||||
type: 'string',
|
||||
defaultValue: '',
|
||||
desc: {
|
||||
'zh-CN': `'更多'按钮触发的下拉面板的宽度`,
|
||||
'en-US': 'Width of the drop-down panel triggered by the More button'
|
||||
},
|
||||
mode: ['pc'],
|
||||
pcDemo: 'more-show-all'
|
||||
},
|
||||
{
|
||||
name: 'title-width',
|
||||
type: 'String',
|
||||
type: 'string',
|
||||
defaultValue: '256px',
|
||||
desc: {
|
||||
'zh-CN': '当 overflow-title 为 true 时,指定页签标题的最大宽度',
|
||||
|
|
|
@ -10,52 +10,20 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import { ref } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { Tabs as TinyTabs, TabItem as TinyTabItem } from '@opentiny/vue'
|
||||
import { iconPopup } from '@opentiny/vue-icon'
|
||||
|
||||
const Tabs = ref([
|
||||
{
|
||||
title: 'Tab 1',
|
||||
name: '1',
|
||||
content: 'Tab 1 content '
|
||||
},
|
||||
{
|
||||
title: 'Tab 2',
|
||||
name: '2',
|
||||
content: 'Tab 2 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 3',
|
||||
name: '3',
|
||||
content: 'Tab 3 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 4',
|
||||
name: '4',
|
||||
content: 'Tab 4 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 5',
|
||||
name: '5',
|
||||
content: 'Tab 5 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 6',
|
||||
name: '6',
|
||||
content: 'Tab 6 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 7',
|
||||
name: '7',
|
||||
content: 'Tab 7 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 8',
|
||||
name: '8',
|
||||
content: 'Tab 8 content'
|
||||
}
|
||||
])
|
||||
|
||||
const Tabs = reactive([])
|
||||
const TinyIconPopup = iconPopup()
|
||||
|
||||
// 创建tabs
|
||||
for (let i = 1; i < 9; i++) {
|
||||
const title = `Tab ${i}`
|
||||
Tabs.push({
|
||||
title,
|
||||
name: i + '',
|
||||
content: `${title} content `
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<tiny-tabs style="width: 400px" show-more-tabs popper-class="custom-class">
|
||||
<template #moreIcon>
|
||||
<icon-popup />
|
||||
<tiny-icon-popup />
|
||||
</template>
|
||||
<tiny-tab-item :key="item.name" v-for="item in Tabs" :title="item.title" :name="item.name">
|
||||
{{ item.content }}
|
||||
|
@ -17,52 +17,22 @@ export default {
|
|||
components: {
|
||||
TinyTabs: Tabs,
|
||||
TinyTabItem: TabItem,
|
||||
IconPopup: iconPopup()
|
||||
TinyIconPopup: iconPopup()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Tabs: [
|
||||
{
|
||||
title: 'Tab 1',
|
||||
name: '1',
|
||||
content: 'Tab 1 content '
|
||||
},
|
||||
{
|
||||
title: 'Tab 2',
|
||||
name: '2',
|
||||
content: 'Tab 2 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 3',
|
||||
name: '3',
|
||||
content: 'Tab 3 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 4',
|
||||
name: '4',
|
||||
content: 'Tab 4 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 5',
|
||||
name: '5',
|
||||
content: 'Tab 5 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 6',
|
||||
name: '6',
|
||||
content: 'Tab 6 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 7',
|
||||
name: '7',
|
||||
content: 'Tab 7 content'
|
||||
},
|
||||
{
|
||||
title: 'Tab 8',
|
||||
name: '8',
|
||||
content: 'Tab 8 content'
|
||||
}
|
||||
]
|
||||
Tabs: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 创建tabs
|
||||
for (let i = 1; i < 9; i++) {
|
||||
const title = `Tab ${i}`
|
||||
this.Tabs.push({
|
||||
title,
|
||||
name: i + '',
|
||||
content: `${title} content `
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<tiny-tabs style="width: 400px" show-more-tabs more-show-all panel-max-height="300px" panel-width="150px">
|
||||
<template #moreIcon>
|
||||
<tiny-icon-popup />
|
||||
</template>
|
||||
<tiny-tab-item :key="item.name" v-for="item in Tabs" :title="item.title" :name="item.name">
|
||||
{{ item.content }}
|
||||
</tiny-tab-item>
|
||||
</tiny-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import { reactive } from 'vue'
|
||||
import { Tabs as TinyTabs, TabItem as TinyTabItem } from '@opentiny/vue'
|
||||
import { iconPopup } from '@opentiny/vue-icon'
|
||||
|
||||
const Tabs = reactive([])
|
||||
const TinyIconPopup = iconPopup()
|
||||
|
||||
// 创建tabs
|
||||
for (let i = 1; i < 101; i++) {
|
||||
const title = `Tab ${i}`
|
||||
Tabs.push({
|
||||
title,
|
||||
name: i + '',
|
||||
content: `${title} content `
|
||||
})
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,53 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('超长数据下拉展示全部,面板长宽可控', async ({ page }) => {
|
||||
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||
await page.goto('tabs#more-show-all')
|
||||
|
||||
const tabNav = page.locator('.tiny-tabs__nav.is-top.is-show-active-bar')
|
||||
const showMoreBtn = page.locator('#more-show-all').getByRole('button')
|
||||
const triggerBtn = page.locator('.tiny-tabs__more-container .tiny-dropdown__trigger.tiny-dropdown-trigger')
|
||||
const panel = page.locator('.tiny-tabs__more-dropdown')
|
||||
|
||||
await showMoreBtn.hover()
|
||||
await showMoreBtn.click()
|
||||
await triggerBtn.click()
|
||||
await page.waitForTimeout(200)
|
||||
await panel.isVisible()
|
||||
await expect(panel).toHaveCSS('width', '150px')
|
||||
await expect(panel).toHaveCSS('max-height', '300px')
|
||||
|
||||
await showMoreBtn.click()
|
||||
await triggerBtn.click()
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Tab 100$/ })
|
||||
.nth(1)
|
||||
.scrollIntoViewIfNeeded()
|
||||
await page.waitForTimeout(200)
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Tab 100$/ })
|
||||
.nth(1)
|
||||
.click()
|
||||
const tab100 = page.getByRole('tab', { name: 'Tab 100' })
|
||||
await tab100.isVisible()
|
||||
await expect(tab100).toHaveClass(/is-active/)
|
||||
|
||||
await showMoreBtn.click()
|
||||
await triggerBtn.click()
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Tab 1$/ })
|
||||
.nth(1)
|
||||
.scrollIntoViewIfNeeded()
|
||||
await page.waitForTimeout(200)
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Tab 1$/ })
|
||||
.nth(1)
|
||||
.click()
|
||||
const tab1 = page.getByRole('tab', { name: 'Tab 1', exact: true })
|
||||
await tab1.isVisible()
|
||||
await expect(tab1).toHaveClass(/is-active/)
|
||||
})
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<tiny-tabs style="width: 400px" show-more-tabs more-show-all panel-max-height="300px" panel-width="150px">
|
||||
<template #moreIcon>
|
||||
<tiny-icon-popup />
|
||||
</template>
|
||||
<tiny-tab-item :key="item.name" v-for="item in Tabs" :title="item.title" :name="item.name">
|
||||
{{ item.content }}
|
||||
</tiny-tab-item>
|
||||
</tiny-tabs>
|
||||
</template>
|
||||
|
||||
<script lang="jsx">
|
||||
import { Tabs, TabItem } from '@opentiny/vue'
|
||||
import { iconPopup } from '@opentiny/vue-icon'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinyTabs: Tabs,
|
||||
TinyTabItem: TabItem,
|
||||
TinyIconPopup: iconPopup()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
Tabs: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 创建tabs
|
||||
for (let i = 1; i < 101; i++) {
|
||||
const title = `Tab ${i}`
|
||||
this.Tabs.push({
|
||||
title,
|
||||
name: i + '',
|
||||
content: `${title} content `
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -91,9 +91,9 @@ export default {
|
|||
},
|
||||
desc: {
|
||||
'zh-CN': `通过 <code>with-close</code> 打开关闭按钮,并监听 <code>close</code> 事件自定义实现删除页签项的逻辑。
|
||||
通过 <code>beforeClose</code> 函数属性,在关闭前回调该函数,其类型声明为:<code>(name: string)=> boolean | Promise<boolean></code>`,
|
||||
'en-US': `Use <code>with-close</code> to enable the close button and listen to the <code>close</code> event to customize the logic for deleting tab items.
|
||||
The <code>beforeClose</code> function attribute is used to call back the function before the function is closed. The type of the function is declared as <code>(name: string)=> boolean | Promise<boolean></code>.`
|
||||
<code>beforeClose</code> 设置删除前的操作,返回为false则取消删除,反之则执行删除。`,
|
||||
'en-US': `Use <code>with-close</code> to open the close button and listen to the <code>close</code> event to customize the logic for deleting tab items.
|
||||
<code>beforeClose</code> sets the operation before the deletion. If the return value is false, the deletion is canceled. Otherwise, the deletion is performed.`
|
||||
},
|
||||
codeFiles: ['tabs-events-close.vue']
|
||||
},
|
||||
|
@ -150,6 +150,20 @@ export default {
|
|||
},
|
||||
codeFiles: ['stretch-wh.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'more-show-all',
|
||||
name: {
|
||||
'zh-CN': '超长数据下拉展示',
|
||||
'en-US': 'Drop-down display of ultra-long data'
|
||||
},
|
||||
desc: {
|
||||
'zh-CN':
|
||||
'通过 <code>more-show-all</code> 设置下拉面板展示全部页签项,<code>panel-max-height</code> 设置面板最大高度; <code>panel-width</code> 设置面板宽度。',
|
||||
'en-US':
|
||||
'Use <code>more-show-all</code> to set the drop-down panel to display all tab items and <code>panel-max-height</code> to set the maximum height of the panel. <code>panel-width</code> sets the width of the panel.'
|
||||
},
|
||||
codeFiles: ['more-show-all.vue']
|
||||
},
|
||||
{
|
||||
demoId: 'custom-tab-title',
|
||||
name: {
|
||||
|
|
|
@ -88,6 +88,12 @@ export const calcMorePanes =
|
|||
const tabs = el.querySelectorAll('.tiny-tabs__item')
|
||||
const tabNavRefs = refs.nav.$refs
|
||||
|
||||
// 此处不同步aui。新规范适配
|
||||
if (props.moreShowAll) {
|
||||
state.showPanesCount = 0
|
||||
return
|
||||
}
|
||||
|
||||
if (tabs && tabs.length) {
|
||||
let tabsAllWidth = 0
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
|
|
|
@ -398,6 +398,7 @@
|
|||
|
||||
&__more-dropdown.@{dropdown-menu-prefix-cls}.@{popper-prefix-cls} {
|
||||
margin-top: var(--ti-tabs-dropdown-more-margin-top); // smb新增
|
||||
overflow: auto; // smb新增
|
||||
}
|
||||
|
||||
&__more-dropdown &__more-item {
|
||||
|
|
|
@ -65,7 +65,11 @@ export const tabsProps = {
|
|||
},
|
||||
beforeClose: Function,
|
||||
overflowTitle: Boolean,
|
||||
titleWidth: String
|
||||
titleWidth: String,
|
||||
// tiny 新增
|
||||
moreShowAll: Boolean,
|
||||
panelMaxHeight: String,
|
||||
panelWidth: String
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -49,7 +49,10 @@ export default defineComponent({
|
|||
'separator',
|
||||
'beforeClose',
|
||||
'overflowTitle',
|
||||
'titleWidth'
|
||||
'titleWidth',
|
||||
'moreShowAll',
|
||||
'panelMaxHeight',
|
||||
'panelWidth'
|
||||
],
|
||||
components: {
|
||||
TabNav,
|
||||
|
@ -84,7 +87,9 @@ export default defineComponent({
|
|||
dropConfig,
|
||||
tooltipConfig,
|
||||
overflowTitle,
|
||||
titleWidth
|
||||
titleWidth,
|
||||
panelMaxHeight,
|
||||
panelWidth
|
||||
} = this
|
||||
|
||||
const newButton =
|
||||
|
@ -120,7 +125,9 @@ export default defineComponent({
|
|||
tooltipConfig,
|
||||
overflowTitle,
|
||||
titleWidth,
|
||||
separator: state.separator
|
||||
separator: state.separator,
|
||||
panelMaxHeight,
|
||||
panelWidth
|
||||
},
|
||||
on: {
|
||||
'tab-drag-start': handleTabDragStart,
|
||||
|
|
|
@ -35,7 +35,9 @@ export const tabNavPcProps = {
|
|||
default: '256px'
|
||||
},
|
||||
// tiny 新增
|
||||
tooltipConfig: [String, Object]
|
||||
tooltipConfig: [String, Object],
|
||||
panelMaxHeight: String,
|
||||
panelWidth: String
|
||||
}
|
||||
|
||||
export const tabNavMobileProps = {
|
||||
|
|
|
@ -111,7 +111,9 @@ export default defineComponent({
|
|||
handleTitleMouseleave,
|
||||
// tiny 新增
|
||||
moreIcon,
|
||||
tooltipConfig
|
||||
tooltipConfig,
|
||||
panelMaxHeight,
|
||||
panelWidth
|
||||
} = this
|
||||
let { panes } = this
|
||||
|
||||
|
@ -174,7 +176,8 @@ export default defineComponent({
|
|||
? h(DropdownMenu, {
|
||||
attrs: {
|
||||
popperClass: 'tiny-tabs-dropdown tiny-tabs__more-dropdown' + (popperClass ? ' ' + popperClass : ''),
|
||||
placement: 'bottom-start'
|
||||
placement: 'bottom-start',
|
||||
style: { maxHeight: panelMaxHeight, width: panelWidth }
|
||||
},
|
||||
scopedSlots: { default: menuSlot }
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue