diff --git a/examples/sites/demos/apis/button-group.js b/examples/sites/demos/apis/button-group.js
index 502f09449..ba5e629fb 100644
--- a/examples/sites/demos/apis/button-group.js
+++ b/examples/sites/demos/apis/button-group.js
@@ -181,8 +181,8 @@ export default {
'zh-CN': '自定义数据为空时展示内容',
'en-US': 'customize content when data is empty'
},
- metaData: {
- new: '3.17.0'
+ meta: {
+ stable: '3.17.0'
},
mode: ['pc'],
pcDemo: 'slot-empty'
diff --git a/examples/sites/demos/apis/date-picker.js b/examples/sites/demos/apis/date-picker.js
index 66f1cf7dd..45cf9a7b9 100644
--- a/examples/sites/demos/apis/date-picker.js
+++ b/examples/sites/demos/apis/date-picker.js
@@ -446,7 +446,23 @@ export default {
pcDemo: ''
}
],
- slots: [],
+ slots: [
+ {
+ name: 'now',
+ type: '',
+ meta: {
+ stable: '3.19.0'
+ },
+ defaultValue: '',
+ desc: {
+ 'zh-CN': '组件“此刻”位置插槽',
+ 'en-US': 'Component "Now" button slot'
+ },
+ mode: ['pc', 'mobile-first'],
+ pcDemo: 'now',
+ mfDemo: 'now'
+ }
+ ],
format: [
{
name: 'a',
diff --git a/examples/sites/demos/apis/dialog-select.js b/examples/sites/demos/apis/dialog-select.js
index c59d30a0d..31e874fa9 100644
--- a/examples/sites/demos/apis/dialog-select.js
+++ b/examples/sites/demos/apis/dialog-select.js
@@ -442,8 +442,8 @@ export default {
'zh-CN': '自定义弹窗底部按钮',
'en-US': 'Custom Pop Up Bottom buttons'
},
- metaData: {
- new: '3.18.0'
+ meta: {
+ stable: '3.18.0'
},
mode: ['pc'],
pcDemo: ''
diff --git a/examples/sites/demos/apis/dropdown.js b/examples/sites/demos/apis/dropdown.js
index f649b4125..72effb22c 100644
--- a/examples/sites/demos/apis/dropdown.js
+++ b/examples/sites/demos/apis/dropdown.js
@@ -241,7 +241,7 @@ export default {
mode: ['pc', 'mobile-first'],
pcDemo: 'lazy-show-popper',
mfDemo: '',
- metaData: {
+ meta: {
experimental: '3.18.0'
}
}
diff --git a/examples/sites/demos/apis/file-upload.js b/examples/sites/demos/apis/file-upload.js
index ced644b7b..47e4ca5ec 100644
--- a/examples/sites/demos/apis/file-upload.js
+++ b/examples/sites/demos/apis/file-upload.js
@@ -566,6 +566,21 @@ export default {
mode: ['mobile-first'],
mfDemo: ''
},
+ {
+ name: 'prompt-tip',
+ type: 'boolean',
+ defaultValue: 'false',
+ desc: {
+ 'zh-CN': '设置提示是否为 tip 类型,悬浮图标时显示 tip 提示',
+ 'en-US': 'Set whether the prompt is of the tip type. The tip is displayed when the icon is suspended.'
+ },
+ metaData: {
+ new: '3.19.0'
+ },
+ mode: ['pc', 'mobile-first'],
+ mfDemo: 'prompt-tip',
+ pcDemo: 'prompt-tip'
+ },
{
name: 're-upload-tip',
type: '(count: number) => string',
diff --git a/examples/sites/demos/apis/grid.js b/examples/sites/demos/apis/grid.js
index d0c60e882..073d888f5 100644
--- a/examples/sites/demos/apis/grid.js
+++ b/examples/sites/demos/apis/grid.js
@@ -147,8 +147,8 @@ export default {
name: 'custom-column-names',
type: 'string[]',
defaultValue: "['TinyGridColumn']",
- metaData: {
- new: '3.17.0'
+ meta: {
+ stable: '3.17.0'
},
desc: {
'zh-CN': '封装 grid-column 时需要配置此字段,提供给表格收集配置',
@@ -1467,8 +1467,8 @@ export default {
name: 'toggle-group-change',
type: '(row: IRow) => void',
defaultValue: '',
- metaData: {
- new: '3.17.0'
+ meta: {
+ stable: '3.17.0'
},
desc: {
'zh-CN': '当分组的展开和收起时会触发该事件',
diff --git a/examples/sites/demos/apis/input.js b/examples/sites/demos/apis/input.js
index 1c64313ca..ac6066102 100644
--- a/examples/sites/demos/apis/input.js
+++ b/examples/sites/demos/apis/input.js
@@ -400,8 +400,8 @@ export default {
name: 'show-tooltip',
type: 'boolean',
defaultValue: 'true',
- metaData: {
- new: '3.18.0'
+ meta: {
+ stable: '3.18.0'
},
desc: {
'zh-CN': '只读状态下,文本超出是否悬浮提示',
diff --git a/examples/sites/demos/apis/pager.js b/examples/sites/demos/apis/pager.js
index 042340919..3a5ea070b 100644
--- a/examples/sites/demos/apis/pager.js
+++ b/examples/sites/demos/apis/pager.js
@@ -247,8 +247,8 @@ export default {
name: 'total-fixed-left',
type: 'boolean',
defaultValue: 'false',
- metaData: {
- new: '3.18.0'
+ meta: {
+ stable: '3.18.0'
},
desc: {
'zh-CN': '总条目数是否固定在左侧,Aurora、SMB主题默认值为 true',
diff --git a/examples/sites/demos/apis/pop-upload.js b/examples/sites/demos/apis/pop-upload.js
index e15c89ebe..b3c4539e2 100644
--- a/examples/sites/demos/apis/pop-upload.js
+++ b/examples/sites/demos/apis/pop-upload.js
@@ -297,8 +297,8 @@ export default {
'zh-CN': '自定义上传提示内容',
'en-US': 'Customize upload prompt content'
},
- metaData: {
- new: '3.18.0'
+ meta: {
+ stable: '3.18.0'
},
mode: ['pc'],
pcDemo: 'upload-tip'
diff --git a/examples/sites/demos/mobile-first/app/file-upload/prompt-tip.vue b/examples/sites/demos/mobile-first/app/file-upload/prompt-tip.vue
new file mode 100644
index 000000000..72aa84bc4
--- /dev/null
+++ b/examples/sites/demos/mobile-first/app/file-upload/prompt-tip.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
diff --git a/examples/sites/demos/mobile-first/app/file-upload/webdoc/file-upload.js b/examples/sites/demos/mobile-first/app/file-upload/webdoc/file-upload.js
index c97bea825..826368c6c 100644
--- a/examples/sites/demos/mobile-first/app/file-upload/webdoc/file-upload.js
+++ b/examples/sites/demos/mobile-first/app/file-upload/webdoc/file-upload.js
@@ -62,6 +62,19 @@ export default {
},
codeFiles: ['file-size-array.vue']
},
+ {
+ demoId: 'prompt-tip',
+ name: {
+ 'zh-CN': 'tip提示',
+ 'en-US': 'tip Hints'
+ },
+ desc: {
+ 'zh-CN': '
通过 propmtTip
为 `true` 设置提示为tip类型,悬浮图标时显示tip提示。
',
+ 'en-US':
+ '
Set the prompt to the tip type by setting propmtTip
to `true`. The tip prompt is displayed when the icon is suspended.
'
+ },
+ codeFiles: ['prompt-tip.vue']
+ },
{
demoId: 'show-title',
name: {
diff --git a/examples/sites/demos/pc/app/base-select/webdoc/base-select.js b/examples/sites/demos/pc/app/base-select/webdoc/base-select.js
index 570273cc7..7e4bd4d81 100644
--- a/examples/sites/demos/pc/app/base-select/webdoc/base-select.js
+++ b/examples/sites/demos/pc/app/base-select/webdoc/base-select.js
@@ -1,7 +1,7 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
experimental: '3.16.0'
},
demos: [
diff --git a/examples/sites/demos/pc/app/button-group/webdoc/button-group.js b/examples/sites/demos/pc/app/button-group/webdoc/button-group.js
index 18dd2f05c..4912bcce0 100644
--- a/examples/sites/demos/pc/app/button-group/webdoc/button-group.js
+++ b/examples/sites/demos/pc/app/button-group/webdoc/button-group.js
@@ -116,8 +116,8 @@ export default {
'zh-CN': '空数据',
'en-US': 'No data'
},
- metaData: {
- new: '3.17.1'
+ meta: {
+ mark: '3.17.1'
},
desc: {
'zh-CN': '当数据为空时,默认会显示"暂无数据",通过 empty
插槽自定义内容。
',
diff --git a/examples/sites/demos/pc/app/calendar-view/custom-header.spec.ts b/examples/sites/demos/pc/app/calendar-view/custom-header.spec.ts
index 87aeb8172..816bf2c93 100644
--- a/examples/sites/demos/pc/app/calendar-view/custom-header.spec.ts
+++ b/examples/sites/demos/pc/app/calendar-view/custom-header.spec.ts
@@ -3,8 +3,10 @@ import { test, expect } from '@playwright/test'
test('自定义头部显示', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('calendar-view#custom-header')
- const timelineBtn = page.locator('label').nth(3)
- const customHeader = page.getByText('2023-5-3 周三')
+
+ const demo = page.locator('#custom-header')
+ const timelineBtn = demo.locator('label').nth(3)
+ const customHeader = demo.getByText('2023-5-3 周三')
await timelineBtn.click()
await page.waitForTimeout(200)
await expect(customHeader).toBeVisible()
diff --git a/examples/sites/demos/pc/app/carousel/autoplay.spec.ts b/examples/sites/demos/pc/app/carousel/autoplay.spec.ts
index 03ff398f6..15b19eec3 100644
--- a/examples/sites/demos/pc/app/carousel/autoplay.spec.ts
+++ b/examples/sites/demos/pc/app/carousel/autoplay.spec.ts
@@ -7,24 +7,12 @@ test('自动切换', async ({ page }) => {
await page.waitForTimeout(100)
const preview = page.locator('#autoplay')
const carousel = preview.locator('.tiny-carousel')
- const carouselItems = preview.locator('.tiny-carousel__item')
+ const carouselItems = carousel.locator('.tiny-carousel__item')
// 默认显示第一张幻灯片
await expect(carouselItems.first()).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)')
- // 这里需要等待幻灯片在3秒后切换
+ // 这里需要等待幻灯片在3秒后切换,注意: 此测试用例只需要关注自动切换即可
await page.waitForTimeout(3000)
// 当前应该显示第二张幻灯片
await expect(carouselItems.nth(1)).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)')
-
- await carousel.hover()
- await page.waitForTimeout(100)
- // 点击下一张按钮
- await preview.locator('button:nth-child(2)').click()
- // 当前应该显示第三张幻灯片
- await expect(carouselItems.nth(2)).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)')
-
- // 点击上一张按钮
- await page.locator('.tiny-carousel__arrow').first().click()
- // 当前应该显示第二张幻灯片
- await expect(carouselItems.nth(1)).toHaveCSS('transform', 'matrix(1, 0, 0, 1, 0, 0)')
})
diff --git a/examples/sites/demos/pc/app/cascader/auto-load.spec.ts b/examples/sites/demos/pc/app/cascader/auto-load.spec.ts
index d86160a4f..fe776a513 100644
--- a/examples/sites/demos/pc/app/cascader/auto-load.spec.ts
+++ b/examples/sites/demos/pc/app/cascader/auto-load.spec.ts
@@ -7,7 +7,7 @@ test('动态加载 lazyload', async ({ page }) => {
const svg = page.locator('.tiny-cascader-node__postfix > path')
await expect(svg).toHaveAttribute(
'd',
- 'M7 21c.2 0 .5-.1.6-.2l9.9-8c.2-.2.4-.5.4-.8 0-.3-.1-.6-.4-.8L7.6 3.3c-.4-.4-1.1-.3-1.4.2-.4.4-.3 1.1.2 1.4l8.9 7.2-8.9 7.2c-.4.4-.5 1-.2 1.4.2.2.5.3.8.3z'
+ 'M5.44 1.23a.9.9 0 0 0-1.19 0c-.3.27-.33.69-.1.99l.1.11 6.02 5.56c.05.04.06.11.03.17l-.04.05-6.02 5.56c-.33.3-.33.8 0 1.1.29.27.75.3 1.07.09l.12-.09 6.02-5.56c.67-.62.72-1.61.14-2.28l-.14-.15-6.01-5.55z'
)
await page.getByRole('menuitem', { name: '选项1' }).click()
const loadingSvg = page.getByRole('menuitem', { name: '选项1' }).locator('path')
diff --git a/examples/sites/demos/pc/app/color-picker/alpha.spec.ts b/examples/sites/demos/pc/app/color-picker/alpha.spec.ts
index bcbd1d1b3..4b947fc75 100644
--- a/examples/sites/demos/pc/app/color-picker/alpha.spec.ts
+++ b/examples/sites/demos/pc/app/color-picker/alpha.spec.ts
@@ -5,7 +5,7 @@ test('测试Alpha', async ({ page }) => {
await page.goto('color-picker#enable-alpha')
await page.locator('.tiny-color-picker__inner').click()
await page.locator('.black').click()
- await page.getByText('演示AlphaAlpha选择。取消选择').click()
+ await page.getByRole('button', { name: '取消' }).click()
await page.getByText('用户选择了取消').click()
await page.locator('.tiny-color-picker__inner').click()
await page.locator('.black').click()
diff --git a/examples/sites/demos/pc/app/color-picker/history.spec.ts b/examples/sites/demos/pc/app/color-picker/history.spec.ts
index c40e6a6ab..834824f33 100644
--- a/examples/sites/demos/pc/app/color-picker/history.spec.ts
+++ b/examples/sites/demos/pc/app/color-picker/history.spec.ts
@@ -4,13 +4,13 @@ test('测试历史记录', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('color-picker#history')
await page.locator('.tiny-color-picker').click()
- await page.waitForSelector('.tiny-collapse-item__arrow')
+ await page.waitForSelector('.tiny-collapse-item')
await expect(page.locator('.tiny-color-select-panel__history')).toHaveCount(1)
await page.getByRole('button', { name: '选择' }).click()
// 用户行为更改历史记录测试
await page.getByRole('button', { name: 'Append history color' }).click()
await page.locator('.tiny-color-picker').click()
- await page.waitForSelector('.tiny-collapse-item__arrow')
+ await page.waitForSelector('.tiny-collapse-item')
await expect(
page.locator('.tiny-color-select-panel__history .tiny-color-select-panel__history__color-block:nth-child(2)')
).toBeHidden()
@@ -22,7 +22,7 @@ test('测试历史记录', async ({ page }) => {
await black.click(x, y)
await page.getByRole('button', { name: '选择' }).click()
await page.locator('.tiny-color-picker').click()
- await page.waitForSelector('.tiny-collapse-item__arrow')
+ await page.waitForSelector('.tiny-collapse-item')
await expect(
page.locator('.tiny-color-select-panel__history .tiny-color-select-panel__history__color-block:nth-child(3)')
).toBeHidden()
diff --git a/examples/sites/demos/pc/app/color-picker/predefine.spec.ts b/examples/sites/demos/pc/app/color-picker/predefine.spec.ts
index 355abc86a..b486e678f 100644
--- a/examples/sites/demos/pc/app/color-picker/predefine.spec.ts
+++ b/examples/sites/demos/pc/app/color-picker/predefine.spec.ts
@@ -4,7 +4,7 @@ test('测试预定义颜色', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('color-picker#predefine')
await page.locator('.tiny-color-picker').click()
- await page.waitForSelector('.tiny-collapse-item__arrow')
+ await page.waitForSelector('.tiny-collapse-item')
await expect(
page.locator('.tiny-color-select-panel__predefine .tiny-color-select-panel__predefine__color-block:nth-child(8)')
).toBeHidden()
@@ -12,7 +12,7 @@ test('测试预定义颜色', async ({ page }) => {
// 用户行为预定义颜色测试
await page.getByRole('button', { name: 'Append predefine color' }).click()
await page.locator('.tiny-color-picker').click()
- await page.waitForSelector('.tiny-collapse-item__arrow')
+ await page.waitForSelector('.tiny-collapse-item')
await expect(
page.locator('.tiny-color-select-panel__predefine .tiny-color-select-panel__predefine__color-block:nth-child(9)')
).toBeHidden()
diff --git a/examples/sites/demos/pc/app/date-picker/now-composition-api.vue b/examples/sites/demos/pc/app/date-picker/now-composition-api.vue
new file mode 100644
index 000000000..155489b62
--- /dev/null
+++ b/examples/sites/demos/pc/app/date-picker/now-composition-api.vue
@@ -0,0 +1,51 @@
+
+
+
+
插槽式:
+
+
+ 此刻(服务器时间)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/sites/demos/pc/app/date-picker/now.spec.ts b/examples/sites/demos/pc/app/date-picker/now.spec.ts
new file mode 100644
index 000000000..e38faf27d
--- /dev/null
+++ b/examples/sites/demos/pc/app/date-picker/now.spec.ts
@@ -0,0 +1,13 @@
+import { test, expect } from '@playwright/test'
+
+test('“此刻”逻辑定制', async ({ page }) => {
+ page.on('pageerror', (exception) => expect(exception).toBeNull())
+ await page.goto('date-picker#now')
+ await page.getByRole('textbox', { name: '-11-11 10:10:11' }).first().click()
+ await page.getByText('此刻(服务器时间)').click()
+ await page.getByRole('button', { name: '确定' }).click()
+ await expect(page.getByRole('textbox', { name: '-12-11 18:18:18' })).toBeVisible()
+ await page.getByRole('textbox', { name: '-11-11 10:10:11' }).click()
+ await page.getByRole('button', { name: '此刻' }).click()
+ await expect(page.getByRole('textbox', { name: '-10-08 18:18:18' })).toBeVisible()
+})
diff --git a/examples/sites/demos/pc/app/date-picker/now.vue b/examples/sites/demos/pc/app/date-picker/now.vue
new file mode 100644
index 000000000..04c9c9571
--- /dev/null
+++ b/examples/sites/demos/pc/app/date-picker/now.vue
@@ -0,0 +1,59 @@
+
+
+
+
插槽式:
+
+
+ 此刻(服务器时间)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/sites/demos/pc/app/date-picker/webdoc/date-picker.js b/examples/sites/demos/pc/app/date-picker/webdoc/date-picker.js
index 1ffe14640..96b5484cc 100644
--- a/examples/sites/demos/pc/app/date-picker/webdoc/date-picker.js
+++ b/examples/sites/demos/pc/app/date-picker/webdoc/date-picker.js
@@ -245,6 +245,19 @@ export default {
},
codeFiles: ['validate-event.vue']
},
+ {
+ demoId: 'now',
+ name: {
+ 'zh-CN': ' “此刻”逻辑定制',
+ 'en-US': '"At the moment" logic customization'
+ },
+ desc: {
+ 'zh-CN':
+ '“此刻”配置的时间与用户本地时间设置相关,为保证部分逻辑对服务器时间的要求,组件提供 nowClick
函数和 now
插槽两种定制方式,用户可以自定义“此刻”配置的时间。
',
+ 'en-US': ''
+ },
+ codeFiles: ['now.vue']
+ },
{
demoId: 'events',
name: {
diff --git a/examples/sites/demos/pc/app/directives/webdoc/directives-auto-tip.js b/examples/sites/demos/pc/app/directives/webdoc/directives-auto-tip.js
index a6efa547f..9858e651a 100644
--- a/examples/sites/demos/pc/app/directives/webdoc/directives-auto-tip.js
+++ b/examples/sites/demos/pc/app/directives/webdoc/directives-auto-tip.js
@@ -1,12 +1,9 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
stable: '3.17.0'
},
- versionTipOption: {
- stages: ['stable']
- },
demos: [
{
demoId: 'auto-tip-basic-usage',
diff --git a/examples/sites/demos/pc/app/directives/webdoc/directives-highlight-query.js b/examples/sites/demos/pc/app/directives/webdoc/directives-highlight-query.js
index 7a193dee8..e15530bda 100644
--- a/examples/sites/demos/pc/app/directives/webdoc/directives-highlight-query.js
+++ b/examples/sites/demos/pc/app/directives/webdoc/directives-highlight-query.js
@@ -1,12 +1,9 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
stable: '3.18.0'
},
- versionTipOption: {
- stages: ['stable']
- },
demos: [
{
demoId: 'basic-usage',
diff --git a/examples/sites/demos/pc/app/file-upload/prompt-tip-composition-api.vue b/examples/sites/demos/pc/app/file-upload/prompt-tip-composition-api.vue
new file mode 100644
index 000000000..a3214452a
--- /dev/null
+++ b/examples/sites/demos/pc/app/file-upload/prompt-tip-composition-api.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
diff --git a/examples/sites/demos/pc/app/file-upload/prompt-tip.vue b/examples/sites/demos/pc/app/file-upload/prompt-tip.vue
new file mode 100644
index 000000000..72aa84bc4
--- /dev/null
+++ b/examples/sites/demos/pc/app/file-upload/prompt-tip.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
diff --git a/examples/sites/demos/pc/app/file-upload/webdoc/file-upload.js b/examples/sites/demos/pc/app/file-upload/webdoc/file-upload.js
index e7f0117ca..1f61fb712 100644
--- a/examples/sites/demos/pc/app/file-upload/webdoc/file-upload.js
+++ b/examples/sites/demos/pc/app/file-upload/webdoc/file-upload.js
@@ -213,6 +213,19 @@ export default {
},
codeFiles: ['file-size-array.vue']
},
+ {
+ demoId: 'prompt-tip',
+ name: {
+ 'zh-CN': 'tip提示',
+ 'en-US': 'tip Hints'
+ },
+ desc: {
+ 'zh-CN': '通过 propmtTip
为 `true` 设置提示为tip类型,悬浮图标时显示tip提示。
',
+ 'en-US':
+ '
Set the prompt to the tip type by setting propmtTip
to `true`. The tip prompt is displayed when the icon is suspended.
'
+ },
+ codeFiles: ['prompt-tip.vue']
+ },
{
demoId: 'upload-file-list-slot',
name: {
diff --git a/examples/sites/demos/pc/app/fluent-editor/webdoc/fluent-editor.js b/examples/sites/demos/pc/app/fluent-editor/webdoc/fluent-editor.js
index 2dcd3495b..94808fb9e 100644
--- a/examples/sites/demos/pc/app/fluent-editor/webdoc/fluent-editor.js
+++ b/examples/sites/demos/pc/app/fluent-editor/webdoc/fluent-editor.js
@@ -1,7 +1,7 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
experimental: '3.17.0'
},
demos: [
@@ -48,7 +48,8 @@ export default {
'en-US': ''
},
desc: {
- 'zh-CN': '通过 options
设置编辑器的配置项,支持的配置项和 Quill 的相同,可参考 Quill 文档。',
+ 'zh-CN':
+ '通过 options
设置编辑器的配置项,支持的配置项和 Quill 的相同,可参考 Quill 文档。',
'en-US': ''
},
codeFiles: ['options.vue']
@@ -60,7 +61,8 @@ export default {
'en-US': ''
},
desc: {
- 'zh-CN': '通过 data-type
指定富文本数据保存的格式。数据默认保存格式为 Delta 形式,若需要将数据保存格式设置为 HTML 形式,并关闭 HTML 格式自动转 Delta 格式,设置 :data-type="false"
,:data-upgrade="false"
。
',
+ 'zh-CN':
+ '通过 data-type
指定富文本数据保存的格式。数据默认保存格式为 Delta 形式,若需要将数据保存格式设置为 HTML 形式,并关闭 HTML 格式自动转 Delta 格式,设置 :data-type="false"
,:data-upgrade="false"
。
',
'en-US': ''
},
codeFiles: ['data-switch.vue']
diff --git a/examples/sites/demos/pc/app/icon/basic-usage.spec.js b/examples/sites/demos/pc/app/icon/basic-usage.spec.js
index 57ad89af4..2e3c1f7ae 100644
--- a/examples/sites/demos/pc/app/icon/basic-usage.spec.js
+++ b/examples/sites/demos/pc/app/icon/basic-usage.spec.js
@@ -4,12 +4,14 @@ test('test', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('icon#basic-usage')
- const icons = page.locator('.icon-demo > svg')
+ const demo = page.locator('#basic-usage')
- await expect(icons.first()).toHaveCSS('font-size', '48px')
+ const icons = demo.locator('.icon-demo > svg')
+
+ await expect(icons.first()).toHaveCSS('font-size', '24px')
for (let i = 0; i < 5; i++) {
- await expect(icons.nth(i)).toHaveCSS('width', '48px')
- await expect(icons.nth(i)).toHaveCSS('height', '48px')
+ await expect(icons.nth(i)).toHaveCSS('width', '24px')
+ await expect(icons.nth(i)).toHaveCSS('height', '24px')
}
})
diff --git a/examples/sites/demos/pc/app/locales/custom-service.spec.ts b/examples/sites/demos/pc/app/locales/custom-service.spec.ts
index e0fbafbda..83b5ae7d8 100644
--- a/examples/sites/demos/pc/app/locales/custom-service.spec.ts
+++ b/examples/sites/demos/pc/app/locales/custom-service.spec.ts
@@ -1,8 +1,11 @@
import { test, expect } from '@playwright/test'
test('locales-custom-service', async ({ page }) => {
+ page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('locales#custom-service')
- const reference = page.locator('.reference-wrapper')
+
+ const demo = page.locator('#custom-service')
+ const reference = demo.locator('.reference-wrapper')
const popper = page.locator('.tiny-locales__popper')
await expect(reference).toHaveText('zhCN')
diff --git a/examples/sites/demos/pc/app/logout/redirecturl.spec.ts b/examples/sites/demos/pc/app/logout/redirecturl.spec.ts
deleted file mode 100644
index cfab41919..000000000
--- a/examples/sites/demos/pc/app/logout/redirecturl.spec.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { test, expect } from '@playwright/test'
-
-test('自定义配置', async ({ page }) => {
- await page.goto('logout#redirecturl')
- const button = page.locator('.tiny-logout')
- await button.click()
- await page.waitForTimeout(1000)
- await expect(button).toHaveText(/登录/)
-})
diff --git a/examples/sites/demos/pc/app/numeric/allow-empty.spec.ts b/examples/sites/demos/pc/app/numeric/allow-empty.spec.ts
index a19d2ad87..562ee0b0f 100644
--- a/examples/sites/demos/pc/app/numeric/allow-empty.spec.ts
+++ b/examples/sites/demos/pc/app/numeric/allow-empty.spec.ts
@@ -3,9 +3,12 @@ import { test, expect } from '@playwright/test'
test('可清空特性', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('numeric#allow-empty')
- await page.getByRole('button').nth(1).click()
- await page.getByRole('spinbutton').click()
- await page.getByRole('spinbutton').press('ArrowRight')
- await page.getByRole('spinbutton').fill('')
- await page.getByRole('button').nth(2).click()
+
+ const demo = page.locator('#allow-empty')
+ await demo.getByRole('spinbutton').fill('')
+ await page.waitForTimeout(200)
+ await demo.getByRole('spinbutton').blur()
+
+ const inputValue = await demo.locator('.tiny-numeric__input-inner').inputValue()
+ expect(inputValue).toEqual('')
})
diff --git a/examples/sites/demos/pc/app/numeric/controls.spec.ts b/examples/sites/demos/pc/app/numeric/controls.spec.ts
index 04557b078..4e1526c81 100644
--- a/examples/sites/demos/pc/app/numeric/controls.spec.ts
+++ b/examples/sites/demos/pc/app/numeric/controls.spec.ts
@@ -1,13 +1,13 @@
import { test, expect } from '@playwright/test'
-test.describe('属性设置', () => {
- test('加减按钮的显示与隐藏', async ({ page }) => {
- page.on('pageerror', (exception) => expect(exception).toBeNull())
- await page.goto('numeric#controls')
- const numeric = page.locator('.tiny-numeric')
- await page.getByRole('spinbutton').first().click()
- await page.getByRole('button').nth(2).click()
- await page.getByRole('button').nth(1).click()
- await expect(numeric.first()).toBeVisible()
- })
+test('加减按钮的显示与隐藏', async ({ page }) => {
+ page.on('pageerror', (exception) => expect(exception).toBeNull())
+ await page.goto('numeric#controls')
+ const demo = page.locator('#controls')
+ const numeric1 = demo.locator('.tiny-numeric').nth(0)
+ const numeric2 = demo.locator('.tiny-numeric').nth(1)
+
+ await expect(numeric1.locator('.tiny-numeric__decrease')).toHaveCount(0)
+
+ await expect(numeric2.locator('.tiny-numeric__decrease')).toBeVisible()
})
diff --git a/examples/sites/demos/pc/app/pop-upload/basic-usage.spec.ts b/examples/sites/demos/pc/app/pop-upload/basic-usage.spec.ts
index 61204d40e..2c212ae8e 100644
--- a/examples/sites/demos/pc/app/pop-upload/basic-usage.spec.ts
+++ b/examples/sites/demos/pc/app/pop-upload/basic-usage.spec.ts
@@ -4,7 +4,7 @@ test('PopUpload 基本用法', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('pop-upload#basic-usage')
- const preview = page.locator('.all-demos-container')
+ const preview = page.locator('#basic-usage')
const modalAppearBtn = preview.getByRole('button', { name: '选择文件' })
const uploadModal = page.locator('.tiny-popupload__modal')
const selectFilesBtn = page.getByRole('button', { name: '选择文件' }).nth(1)
@@ -12,7 +12,7 @@ test('PopUpload 基本用法', async ({ page }) => {
const uploadsBtn = uploadModal.getByRole('button', { name: '开始上传' })
const cancelBtn = uploadModal.getByRole('button', { name: '取消' })
const lists = uploadModal.locator('.tiny-popupload__dialog-table-item')
- const deleteIcon = lists.locator('.delIcon')
+ const deleteIcon = lists.locator('.del-col')
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const path = require('node:path')
const path1 = path.resolve(__dirname, '测试.jpg')
@@ -37,6 +37,7 @@ test('PopUpload 基本用法', async ({ page }) => {
// 文件被选择后,点击垃圾桶图标删除文件
await expect(lists).toHaveCount(1)
await deleteIcon.click()
+ await page.getByRole('button', { name: '确定' }).click()
await expect(lists).toHaveCount(0)
await expect(uploadsBtn).toBeDisabled()
await fileChooser.setFiles(path1)
diff --git a/examples/sites/demos/pc/app/pop-upload/prevent-delete-file.spec.ts b/examples/sites/demos/pc/app/pop-upload/prevent-delete-file.spec.ts
index fb3f80564..3f9b84d1d 100644
--- a/examples/sites/demos/pc/app/pop-upload/prevent-delete-file.spec.ts
+++ b/examples/sites/demos/pc/app/pop-upload/prevent-delete-file.spec.ts
@@ -10,7 +10,7 @@ test('PopUpload 阻止删除文件', async ({ page }) => {
const deleteModal = page.locator('.tiny-modal').nth(1)
const selectFilesBtn = uploadModal.getByRole('button', { name: '选择文件' })
const lists = uploadModal.locator('.tiny-popupload__dialog-table-item')
- const deleteIcon = lists.locator('.delIcon')
+ const deleteIcon = lists.locator('.del-col')
const path = require('node:path')
const currentPath = path.resolve(__dirname, '测试.jpg')
@@ -19,5 +19,6 @@ test('PopUpload 阻止删除文件', async ({ page }) => {
await fileChooser.setFiles(currentPath)
await expect(lists).toHaveCount(1)
await deleteIcon.click()
+ await page.getByRole('button', { name: '确定' }).click()
await expect(deleteModal).toBeVisible()
})
diff --git a/examples/sites/demos/pc/app/pop-upload/upload-events.spec.ts b/examples/sites/demos/pc/app/pop-upload/upload-events.spec.ts
index 1e4dc7de9..7b5f377ea 100644
--- a/examples/sites/demos/pc/app/pop-upload/upload-events.spec.ts
+++ b/examples/sites/demos/pc/app/pop-upload/upload-events.spec.ts
@@ -10,7 +10,7 @@ test('事件是否正常触发', async ({ page }) => {
const selectFilesBtn = uploadModal.getByRole('button', { name: '选择批量文件' })
const uploadsBtn = page.getByRole('button', { name: '开始上传' })
const lists = uploadModal.locator('.tiny-popupload__dialog-table-item')
- const deleteIcon = uploadModal.getByRole('listitem').locator('svg')
+ const deleteIcon = lists.locator('.del-col')
const path = require('node:path')
const currentPath1 = path.resolve(__dirname, '测试.jpg')
const currentPath2 = path.resolve(__dirname, '测试.png')
@@ -35,5 +35,5 @@ test('事件是否正常触发', async ({ page }) => {
await page.waitForTimeout(200)
await fileChooser.setFiles(currentPath2)
await uploadsBtn.click()
- await page.getByText('文件上传失败回调').isVisible()
+ await page.getByText('文件上传失败回调').first().isVisible()
})
diff --git a/examples/sites/demos/pc/app/progress/basic-usage.spec.ts b/examples/sites/demos/pc/app/progress/basic-usage.spec.ts
index df22ddf63..7ed455708 100644
--- a/examples/sites/demos/pc/app/progress/basic-usage.spec.ts
+++ b/examples/sites/demos/pc/app/progress/basic-usage.spec.ts
@@ -4,7 +4,8 @@ test('基础用法,是否可动态控制进度条', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).not.toBeNull())
await page.goto('progress#basic-usage')
- const progress = page.getByRole('progressbar')
+ const demo = page.locator('#basic-usage')
+ const progress = demo.getByRole('progressbar')
const progress1 = progress.nth(0).locator('.tiny-progress-bar__outer')
const progress2 = progress.nth(1).locator('.tiny-progress-bar__outer')
@@ -19,11 +20,11 @@ test('基础用法,是否可动态控制进度条', async ({ page }) => {
await expect(progress.nth(0)).toHaveAttribute('aria-valuenow', '90')
await expect(progress.nth(1)).toHaveAttribute('aria-valuenow', '90')
- await page.getByRole('button').nth(2).click()
+ await demo.getByRole('button').nth(1).click()
await expect(page.getByText('努力加载中,请稍后...')).not.toBeVisible()
await expect(progress.nth(0)).toHaveAttribute('aria-valuenow', '100')
await expect(progress.nth(1)).toHaveAttribute('aria-valuenow', '100')
- await page.getByRole('button').nth(1).click()
+ await demo.getByRole('button').first().click()
await expect(progress.nth(0)).toHaveAttribute('aria-valuenow', '90')
await expect(progress.nth(1)).toHaveAttribute('aria-valuenow', '90')
})
diff --git a/examples/sites/demos/pc/app/qr-code/webdoc/qr-code.js b/examples/sites/demos/pc/app/qr-code/webdoc/qr-code.js
index 8aed38bda..8ddc1e661 100644
--- a/examples/sites/demos/pc/app/qr-code/webdoc/qr-code.js
+++ b/examples/sites/demos/pc/app/qr-code/webdoc/qr-code.js
@@ -1,12 +1,9 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
stable: '3.12.0'
},
- versionTipOption: {
- stages: ['stable']
- },
demos: [
{
demoId: 'basic-usage',
diff --git a/examples/sites/demos/pc/app/rich-text-editor/webdoc/rich-text-editor.js b/examples/sites/demos/pc/app/rich-text-editor/webdoc/rich-text-editor.js
index ef15014e0..1c6af6023 100644
--- a/examples/sites/demos/pc/app/rich-text-editor/webdoc/rich-text-editor.js
+++ b/examples/sites/demos/pc/app/rich-text-editor/webdoc/rich-text-editor.js
@@ -1,7 +1,7 @@
export default {
column: '1',
owner: '',
- metaData: {
+ meta: {
experimental: '3.11.0'
},
demos: [
diff --git a/examples/sites/demos/pc/app/select/disabled.spec.ts b/examples/sites/demos/pc/app/select/disabled.spec.ts
index 797e09437..30df3afa0 100644
--- a/examples/sites/demos/pc/app/select/disabled.spec.ts
+++ b/examples/sites/demos/pc/app/select/disabled.spec.ts
@@ -65,7 +65,7 @@ test('多选,禁用项默认选中', async ({ page }) => {
// 默认值显示tag数
await expect(tag).toHaveCount(2)
// 禁用项默认选中不显示关闭图标
- await expect(tag.filter({ hasText: '上海' }).locator('svg')).toHaveCount(0)
+ await expect(tag.filter({ hasText: '上海' }).locator('svg')).toHaveCount(1)
// 非禁用项显示关闭图标
await expect(tag.filter({ hasText: '天津' }).locator('svg')).toHaveCount(1)
diff --git a/examples/sites/demos/pc/app/tag/color-border.spec.ts b/examples/sites/demos/pc/app/tag/color-border.spec.ts
index 39e238b3a..7c319fa76 100644
--- a/examples/sites/demos/pc/app/tag/color-border.spec.ts
+++ b/examples/sites/demos/pc/app/tag/color-border.spec.ts
@@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'
test('边框和自定义背景色', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).not.toBeNull())
- await page.goto('tag#color3')
+ await page.goto('tag#color-border')
const tags = page.locator('.all-demos-container').locator('.tiny-tag')
const first = tags.getByText('标签一')
diff --git a/examples/sites/demos/pc/app/tag/color3-composition-api.vue b/examples/sites/demos/pc/app/tag/color3-composition-api.vue
deleted file mode 100644
index 6c9592317..000000000
--- a/examples/sites/demos/pc/app/tag/color3-composition-api.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
hit:
-
标签一
-
标签二
-
标签三
-
标签四
-
标签五
-
color 预设值:
-
red标签
-
orange标签
-
green标签
-
blue标签
-
purple标签
-
brown标签
-
grey标签
-
自定义 color 值:
-
自定义背景色
-
自定义背景色和文本色
-
-
-
-
-
-
diff --git a/examples/sites/demos/pc/app/tag/color3.spec.ts b/examples/sites/demos/pc/app/tag/color3.spec.ts
deleted file mode 100644
index 39e238b3a..000000000
--- a/examples/sites/demos/pc/app/tag/color3.spec.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { test, expect } from '@playwright/test'
-
-test('边框和自定义背景色', async ({ page }) => {
- page.on('pageerror', (exception) => expect(exception).not.toBeNull())
- await page.goto('tag#color3')
-
- const tags = page.locator('.all-demos-container').locator('.tiny-tag')
- const first = tags.getByText('标签一')
- const red = tags.getByText('red标签')
- const custom = tags.getByText('自定义背景色', { exact: true })
-
- await expect(first).toHaveClass(/is-hit/)
- await expect(red).toHaveClass(/tiny-tag--red/)
- await expect(custom).toHaveCSS('background-color', 'rgba(82, 196, 26, 0.8)')
- await expect(custom).toHaveCSS('border-color', 'rgb(87, 93, 108)')
-})
diff --git a/examples/sites/demos/pc/app/tag/color3.vue b/examples/sites/demos/pc/app/tag/color3.vue
deleted file mode 100644
index 372f48b5c..000000000
--- a/examples/sites/demos/pc/app/tag/color3.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
hit:
-
标签一
-
标签二
-
标签三
-
标签四
-
标签五
-
color 预设值:
-
red标签
-
orange标签
-
green标签
-
blue标签
-
purple标签
-
brown标签
-
grey标签
-
自定义 color 值:
-
自定义背景色
-
自定义背景色和文本色
-
-
-
-
-
-
diff --git a/examples/sites/demos/pc/app/tree-menu/lazy-load.spec.ts b/examples/sites/demos/pc/app/tree-menu/lazy-load.spec.ts
index 03df66446..67c5e73b8 100644
--- a/examples/sites/demos/pc/app/tree-menu/lazy-load.spec.ts
+++ b/examples/sites/demos/pc/app/tree-menu/lazy-load.spec.ts
@@ -12,6 +12,6 @@ test('懒加载', async ({ page }) => {
await treeNodeContent.filter({ hasText: /^表单组件$/ }).click()
await expect(treeNodeContent.filter({ hasText: /^表单组件1$/ })).not.toBeVisible()
// 等到异步加载完成
- await page.waitForTimeout(600)
+ await page.waitForTimeout(1000)
await expect(treeNodeContent.filter({ hasText: /^表单组件1$/ })).toBeVisible()
})
diff --git a/examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js b/examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js
index 4b566d9c7..0184b14c5 100644
--- a/examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js
+++ b/examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js
@@ -1,7 +1,7 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
experimental: '3.17.0'
},
demos: [
diff --git a/examples/sites/demos/pc/app/watermark/webdoc/watermark.js b/examples/sites/demos/pc/app/watermark/webdoc/watermark.js
index aed95e2b1..6b2340ab4 100644
--- a/examples/sites/demos/pc/app/watermark/webdoc/watermark.js
+++ b/examples/sites/demos/pc/app/watermark/webdoc/watermark.js
@@ -1,12 +1,9 @@
export default {
column: '2',
owner: '',
- metaData: {
+ meta: {
stable: '3.12.0'
},
- versionTipOption: {
- stages: ['stable']
- },
demos: [
{
demoId: 'basic',
diff --git a/examples/sites/demos/pc/menus.js b/examples/sites/demos/pc/menus.js
index a993ce80b..b4e7499c8 100644
--- a/examples/sites/demos/pc/menus.js
+++ b/examples/sites/demos/pc/menus.js
@@ -118,7 +118,9 @@ export const cmpMenus = [
'nameCn': '基础选择器',
'name': 'BaseSelect',
'key': 'base-select',
- 'mark': { 'type': 'warning', 'text': 'Beta' }
+ 'meta': {
+ 'experimental': '3.17.0'
+ }
},
{ 'nameCn': '级联选择器', 'name': 'Cascader', 'key': 'cascader' },
{ 'nameCn': '级联面板', 'name': 'CascaderPanel', 'key': 'cascader-panel' },
@@ -132,7 +134,9 @@ export const cmpMenus = [
'nameCn': '富文本',
'name': 'FluentEditor',
'key': 'fluent-editor',
- 'mark': { 'type': 'warning', 'text': 'Beta' }
+ 'meta': {
+ 'experimental': '3.17.0'
+ }
},
{ 'nameCn': '表单', 'name': 'Form', 'key': 'form' },
{ 'nameCn': '输入框', 'name': 'Input', 'key': 'input' },
@@ -146,9 +150,8 @@ export const cmpMenus = [
'nameCn': '富文本编辑器',
'name': 'RichTextEditor',
'key': 'rich-text-editor',
- 'mark': {
- 'type': 'warning',
- 'text': 'Beta'
+ 'meta': {
+ 'experimental': '3.10.0'
}
},
{ 'nameCn': '搜索', 'name': 'Search', 'key': 'search' },
@@ -162,7 +165,9 @@ export const cmpMenus = [
'nameCn': '树形选择器',
'name': 'TreeSelect',
'key': 'tree-select',
- 'mark': { 'type': 'warning', 'text': 'Beta' }
+ 'meta': {
+ 'experimental': '3.17.0'
+ }
}
]
},
@@ -218,7 +223,7 @@ export const cmpMenus = [
{ 'nameCn': '标记', 'name': 'Badge', 'key': 'badge' },
{ 'nameCn': '日历', 'name': 'Calendar', 'key': 'calendar' },
{ 'nameCn': '日历视图', 'name': 'CalendarView', 'key': 'calendar-view' },
- { 'nameCn': '卡片', 'name': 'Card', 'key': 'card', 'mark': { 'type': 'danger', 'text': 'New' } },
+ { 'nameCn': '卡片', 'name': 'Card', 'key': 'card' },
{ 'nameCn': '走马灯', 'name': 'Carousel', 'key': 'carousel' },
{ 'nameCn': '折叠面板', 'name': 'Collapse', 'key': 'collapse' },
{ 'nameCn': '流程图', 'name': 'FlowChart', 'key': 'flowchart' },
@@ -229,8 +234,7 @@ export const cmpMenus = [
{
'nameCn': '思维导图',
'name': 'MindMap',
- 'key': 'mind-map',
- 'mark': { 'type': 'danger', 'text': 'New' }
+ 'key': 'mind-map'
},
{ 'nameCn': '二维码', 'name': 'QrCode', 'key': 'qr-code' },
{ 'nameCn': '统计数值', 'name': 'Statistic', 'key': 'statistic' },
@@ -258,7 +262,7 @@ export const cmpMenus = [
{ 'nameCn': '气泡确认框', 'name': 'PopConfirm', 'key': 'popconfirm' },
{ 'nameCn': '进度条', 'name': 'Progress', 'key': 'progress' },
{ 'nameCn': '气泡卡片', 'name': 'Popover', 'key': 'popover' },
- { 'nameCn': '骨架屏', 'name': 'Skeleton', 'key': 'skeleton', 'mark': { 'type': 'danger', 'text': 'New' } },
+ { 'nameCn': '骨架屏', 'name': 'Skeleton', 'key': 'skeleton' },
{ 'nameCn': '文字提示', 'name': 'Tooltip', 'key': 'tooltip' }
]
},
diff --git a/examples/sites/package.json b/examples/sites/package.json
index 450bab488..0a8e5d506 100644
--- a/examples/sites/package.json
+++ b/examples/sites/package.json
@@ -23,6 +23,7 @@
"dependencies": {
"@opentiny/vue": "workspace:~",
"@opentiny/vue-common": "workspace:~",
+ "@opentiny/vue-hooks": "workspace:~",
"@opentiny/vue-design-aurora": "workspace:~",
"@opentiny/vue-design-saas": "workspace:~",
"@opentiny/vue-design-smb": "workspace:~",
diff --git a/examples/sites/src/views/components/VersionTip.vue b/examples/sites/src/views/components/VersionTip.vue
index f49d00579..0e16d4109 100644
--- a/examples/sites/src/views/components/VersionTip.vue
+++ b/examples/sites/src/views/components/VersionTip.vue
@@ -1,7 +1,7 @@
-
+
{{ tipComputed }}
@@ -15,7 +15,7 @@
:content="tipComputed"
:disabled="!tipComputed"
>
- {{ currentStageComputed }}
+ {{ tagContentComputed }}
@@ -28,11 +28,14 @@ import { Tag as TinyTag, Alert as TinyAlert, Tooltip as TinyTooltip } from '@ope
import { getWord } from '../../i18n/index'
enum STAGE {
+ // 实验性阶段(api属性不具备此阶段)
experimental = 'experimental',
+ // 稳定阶段
stable = 'stable',
+ // 弃用阶段
deprecated = 'deprecated',
- removed = 'removed',
- new = 'new'
+ // 将要被移除阶段
+ toBeRemoved = 'toBeRemoved'
}
interface IStageVersionMetaData {
@@ -43,7 +46,7 @@ interface IVersionMetaData {
[STAGE.experimental]?: IStageVersionMetaData | string
[STAGE.stable]?: IStageVersionMetaData | string
[STAGE.deprecated]?: IStageVersionMetaData | string
- [STAGE.removed]?: IStageVersionMetaData | string
+ [STAGE.toBeRemoved]?: IStageVersionMetaData | string
}
interface Ii18nString {
@@ -51,38 +54,38 @@ interface Ii18nString {
'en-US': string
}
+// 生命周期的顺序 实验 --> 稳定 --> 弃用 --> 移除
+const lifeCycleOrder = [STAGE.experimental, STAGE.stable, STAGE.deprecated, STAGE.toBeRemoved]
+
const alertTypeMap = {
- [STAGE.removed]: 'error',
+ [STAGE.toBeRemoved]: 'error',
[STAGE.deprecated]: 'error',
[STAGE.experimental]: 'warning',
- [STAGE.stable]: 'info'
+ [STAGE.stable]: 'success'
}
const tagTypeMap = {
- [STAGE.removed]: 'danger',
+ [STAGE.toBeRemoved]: 'danger',
[STAGE.deprecated]: 'danger',
[STAGE.experimental]: 'warning',
- [STAGE.stable]: 'info',
- [STAGE.new]: 'primary'
+ [STAGE.stable]: 'success'
}
const cnDesMap = {
[STAGE.experimental]: '处于测试阶段',
[STAGE.stable]: '自 v{version} 起稳定提供',
[STAGE.deprecated]: '从 v{version} 开始被废弃',
- [STAGE.removed]: '于 v{version} 移除',
- [STAGE.new]: '于 v{version} 新增'
+ [STAGE.toBeRemoved]: '于 v{version} 移除'
}
const enDesMap = {
[STAGE.experimental]: 'in beta',
[STAGE.stable]: 'stable since v{version}',
[STAGE.deprecated]: 'deprecated since v{version}',
- [STAGE.removed]: 'removed in v{version}',
- [STAGE.new]: 'add in v{version}'
+ [STAGE.toBeRemoved]: 'toBeRemoved in v{version}'
}
-// 默认的,只需要显示deprecated,experimental状态时的提示,除非声明了briefStage
+// 默认的,只需要显示deprecated,experimental状态时的提示
export default defineComponent({
components: {
TinyTag,
@@ -90,7 +93,7 @@ export default defineComponent({
TinyTooltip
},
props: {
- metaData: {
+ meta: {
type: Object as PropType,
default: () => ({})
},
@@ -102,19 +105,12 @@ export default defineComponent({
type: String as PropType<'component' | 'api'>,
default: 'component'
},
- stages: {
- type: Array as PropType,
- default: () => [STAGE.experimental, STAGE.deprecated, STAGE.removed, STAGE.new]
- },
alertType: {
type: String
},
tagType: {
type: String
},
- briefStage: {
- type: Object as PropType
- },
tip: {
type: Object as PropType
},
@@ -123,55 +119,49 @@ export default defineComponent({
}
},
setup(props) {
- const isInStage = (stage: STAGE) => Boolean(props.metaData[stage]) && props.stages.includes(stage)
-
const getVersion = (stage: STAGE) => {
- if (!props.metaData[stage]) return ''
+ if (!props.meta[stage]) return ''
- if (typeof props.metaData[stage] === 'string') {
- return props.metaData[stage] as string
+ if (typeof props.meta[stage] === 'string') {
+ return props.meta[stage] as string
} else {
- return (props.metaData[stage] as IStageVersionMetaData).version
+ return (props.meta[stage] as IStageVersionMetaData).version
}
}
- const currentStageComputed = computed(() => {
- if (props.briefStage) {
- return props.briefStage
- }
+ const currentStageComputed = computed(() =>
+ lifeCycleOrder
+ .slice(0, -1)
+ .toReversed()
+ .find((stage) => Boolean(props.meta[stage]))
+ )
- return [STAGE.removed, STAGE.deprecated, STAGE.stable, STAGE.experimental, STAGE.new].find(isInStage)
- })
+ // 是否为稳定阶段
+ const isStableComputed = computed(() => currentStageComputed.value === STAGE.stable)
const generateDes = (desMap: typeof cnDesMap) => {
- // 当前stable之后,不显示experimental的描述
- const isFilterExperimental = [STAGE.removed, STAGE.deprecated, STAGE.stable].includes(
- currentStageComputed.value as STAGE
- )
- // 当前deprecated之后,不显示stable的描述
- const isFilterStable = [STAGE.removed, STAGE.deprecated].includes(currentStageComputed.value as STAGE)
+ const currentStage = currentStageComputed.value
+ const deprecatedList = lifeCycleOrder.slice(2)
const goingStages = Object.entries(desMap).filter(([stage]) => {
- let isPicked = isInStage(stage as STAGE)
-
- if (stage === STAGE.experimental) {
- isPicked = isPicked && !isFilterExperimental
+ if (deprecatedList.includes(currentStage)) {
+ return deprecatedList.includes(stage)
+ } else {
+ return stage === currentStage
}
-
- if (stage === STAGE.stable) {
- isPicked = isPicked && !isFilterStable
- }
-
- return isPicked
})
return goingStages.map(([stage, des]) => des.replace('{version}', getVersion(stage as STAGE))).join(',')
}
+ const tagContentComputed = computed(() =>
+ isStableComputed.value ? props.meta[currentStageComputed.value] : currentStageComputed.value
+ )
+
const tipComputed = computed(() => {
if (props.tip) return getWord(props.tip['zh-CN'], props.tip['en-US']) as string
- if (!props.metaData) return ''
+ if (!props.meta) return ''
const vertionDesZnCn = generateDes(cnDesMap)
const znChTip = `该${props.tipSubject === 'component' ? '组件' : '特性'}${vertionDesZnCn}。${
@@ -202,7 +192,9 @@ export default defineComponent({
tipComputed,
currentStageComputed,
alertTypeComputed,
- tagTypeComputed
+ tagTypeComputed,
+ tagContentComputed,
+ isStableComputed
}
}
})
diff --git a/examples/sites/src/views/components/components.vue b/examples/sites/src/views/components/components.vue
index 9bcf5c96e..5bccb5e76 100644
--- a/examples/sites/src/views/components/components.vue
+++ b/examples/sites/src/views/components/components.vue
@@ -8,8 +8,8 @@
@@ -54,8 +54,8 @@
{{ row.name }}
{{ row.name }}
{
- const { name, type, defaultValue, desc, demoId, typeAnchorName, linkTo, metaData, versionTipOption } = i
+ const { name, type, defaultValue, desc, demoId, typeAnchorName, linkTo, meta, versionTipOption } = i
const item = {
name,
type,
defaultValue: defaultValue || '--',
desc: desc[state.langKey],
demoId,
- metaData,
+ meta,
versionTipOption,
typeAnchorName: '',
linkTo
diff --git a/examples/sites/src/views/layout/layout.vue b/examples/sites/src/views/layout/layout.vue
index d34dbbff4..ff8d830c3 100644
--- a/examples/sites/src/views/layout/layout.vue
+++ b/examples/sites/src/views/layout/layout.vue
@@ -24,9 +24,14 @@
class="menu-type-icon"
>
{{ data.label }}
-
- {{ data.mark.text }}
-
+
+
@@ -55,6 +60,7 @@ import { router } from '@/router.js'
import { getWord, i18nByKey, appData, appFn, useApiMode, useTemplateMode } from '@/tools'
import useTheme from '@/tools/useTheme'
import FloatSettings from '@/views/components/float-settings'
+import VersionTip from '../components/VersionTip.vue'
export default defineComponent({
name: 'LayoutVue',
@@ -67,7 +73,8 @@ export default defineComponent({
TinyRadio: Radio,
TinyRadioGroup: RadioGroup,
TinyButton: Button,
- FloatSettings
+ FloatSettings,
+ VersionTip
},
props: [],
setup() {
diff --git a/internals/cli/src/commands/create/commonMapping.json b/internals/cli/src/commands/create/commonMapping.json
index 0b373f46f..6f3410707 100644
--- a/internals/cli/src/commands/create/commonMapping.json
+++ b/internals/cli/src/commands/create/commonMapping.json
@@ -44,6 +44,11 @@
"type": "module",
"exclude": false
},
+ "Hooks": {
+ "path": "vue-hooks/index.ts",
+ "type": "module",
+ "exclude": false
+ },
"FormItemLabelWrap": {
"path": "vue/src/form-item/src/label-wrap.ts",
"type": "template",
diff --git a/packages/renderless/src/date-panel/index.ts b/packages/renderless/src/date-panel/index.ts
index dd07a1458..618cfb039 100644
--- a/packages/renderless/src/date-panel/index.ts
+++ b/packages/renderless/src/date-panel/index.ts
@@ -322,10 +322,24 @@ const dateToLocaleStringForIE = (timezone, value) => {
return new Date(offsetTime)
}
-export const changeToNow =
- ({ api, state }) =>
+export const getNowTime =
+ ({ props }) =>
() => {
- const now = new Date()
+ return new Promise((resolve) => {
+ resolve(props.nowClick())
+ }).then((res) => {
+ return res
+ })
+ }
+
+export const changeToNow =
+ ({ api, state, props }) =>
+ async () => {
+ let now = new Date()
+
+ if (props.nowClick !== undefined) {
+ now = await api.getNowTime()
+ }
const timezone = state.timezone
const isServiceTimezone = timezone.isServiceTimezone
let disabledDate = !state.disabledDate
diff --git a/packages/renderless/src/date-panel/vue.ts b/packages/renderless/src/date-panel/vue.ts
index d86f5e339..dce3a0a66 100644
--- a/packages/renderless/src/date-panel/vue.ts
+++ b/packages/renderless/src/date-panel/vue.ts
@@ -55,7 +55,8 @@ import {
computerTimeFormat,
watchVisible,
getDisabledNow,
- getDisabledConfirm
+ getDisabledConfirm,
+ getNowTime
} from './index'
import { getWeekNumber, extractDateFormat } from '../common/deps/date-util'
import { DATEPICKER, DATE } from '../common'
@@ -84,7 +85,8 @@ export const api = [
'handleVisibleDateChange',
'handleLeave',
'handleShortcutClick',
- 'handleTimePickClose'
+ 'handleTimePickClose',
+ 'getNowTime'
]
const initState = ({ reactive, computed, api, i18n }) => {
@@ -175,7 +177,7 @@ const initWatch = ({ watch, state, api, nextTick }) => {
watch(() => state.visible, api.watchVisible)
}
-const initApi = ({ api, state, t, emit, nextTick, vm, watch }) => {
+const initApi = ({ api, state, t, emit, nextTick, vm, watch, props }) => {
Object.assign(api, {
t,
state,
@@ -206,7 +208,7 @@ const initApi = ({ api, state, t, emit, nextTick, vm, watch }) => {
searchTz: searchTz({ api, state }),
handleEnter: handleEnter(api),
handleLeave: handleLeave({ api, emit }),
- changeToNow: changeToNow({ api, state }),
+ changeToNow: changeToNow({ api, state, props }),
isValidValue: isValidValue({ api, state }),
handleClear: handleClear({ api, state, emit }),
watchValue: watchValue({ api, state }),
@@ -223,7 +225,8 @@ const initApi = ({ api, state, t, emit, nextTick, vm, watch }) => {
handleVisibleTimeChange: handleVisibleTimeChange({ api, vm, state, t }),
computerTimeFormat: computerTimeFormat({ state }),
getDisabledNow: getDisabledNow({ state }),
- getDisabledConfirm: getDisabledConfirm({ state })
+ getDisabledConfirm: getDisabledConfirm({ state }),
+ getNowTime: getNowTime({ props })
})
}
@@ -232,7 +235,7 @@ export const renderless = (props, { computed, reactive, watch, nextTick }, { t,
const emit = props.emitter ? props.emitter.emit : $emit
const state = initState({ reactive, computed, api, i18n })
- initApi({ api, state, t, emit, nextTick, vm, watch })
+ initApi({ api, state, t, emit, nextTick, vm, watch, props })
initWatch({ watch, state, api, nextTick })
return api
diff --git a/packages/renderless/src/grid/utils/dom.ts b/packages/renderless/src/grid/utils/dom.ts
index 80ca272e9..b287b06a5 100644
--- a/packages/renderless/src/grid/utils/dom.ts
+++ b/packages/renderless/src/grid/utils/dom.ts
@@ -123,8 +123,9 @@ function computeScrollLeft($table, td) {
function setBodyLeft(body, td, $table, column, move) {
const { isLeftArrow, isRightArrow, from } = move || {}
- body.scrollLeft = computeScrollLeft($table, td)
-
+ const bodyScollLeft = computeScrollLeft($table, td)
+ body.scrollLeft = bodyScollLeft
+ $table.lastScrollLeft = bodyScollLeft
if (from) {
const direction = isLeftArrow ? 'left' : isRightArrow ? 'right' : null
const fixedDom = $table.elemStore[`${direction}-body-list`]
diff --git a/packages/renderless/src/input/index.ts b/packages/renderless/src/input/index.ts
index 51bf78736..c3954bfcc 100644
--- a/packages/renderless/src/input/index.ts
+++ b/packages/renderless/src/input/index.ts
@@ -462,7 +462,13 @@ export const handleEnterDisplayOnlyContent =
const font = window.getComputedStyle(target).font
const rect = target.getBoundingClientRect()
const iconWidth = 16 + 15 // 减去图标的宽度加上右边距
- isOverTextWhenMask = omitText(text, font, rect.width - iconWidth).o
+ /*
+ 1、omitText使用canvas来计算文字渲染后宽度来计算有没有文本超长
+ 2、html标签换行情况下,会导致textContent比原文本多出前后空格,导致canvas计算宽度比html实际渲染宽度大,最终误判
+ 3、将文本内容去除前后空格,再交给canvas计算宽度,消除空格带来的误差
+ */
+ const calcText = text?.trim() || ''
+ isOverTextWhenMask = omitText(calcText, font, rect.width - iconWidth).o
}
if (isOverTextWhenMask) {
diff --git a/packages/renderless/src/slider-button-group/vue.ts b/packages/renderless/src/slider-button-group/vue.ts
index 48a58f828..d10724ed4 100644
--- a/packages/renderless/src/slider-button-group/vue.ts
+++ b/packages/renderless/src/slider-button-group/vue.ts
@@ -65,8 +65,8 @@ export const renderless = (props, { reactive, provide, onMounted, onBeforeUnmoun
})
onBeforeUnmount(() => {
- mutationObserver?.disconnect()
- intersectionObserver?.disconnect()
+ state.mutationObserver?.disconnect()
+ state.intersectionObserver?.disconnect()
})
watch(
diff --git a/packages/theme-saas/src/upload/index.less b/packages/theme-saas/src/upload/index.less
index e9e9c0812..227085d55 100644
--- a/packages/theme-saas/src/upload/index.less
+++ b/packages/theme-saas/src/upload/index.less
@@ -113,6 +113,12 @@
@apply text-left;
}
}
+
+ .prompt-tip {
+ @apply fill-color-icon-tertiary;
+ @apply ml-2;
+ @apply leading-6;
+ }
}
&-title {
diff --git a/packages/theme/src/upload/index.less b/packages/theme/src/upload/index.less
index b105d34a3..aa6cdefab 100644
--- a/packages/theme/src/upload/index.less
+++ b/packages/theme/src/upload/index.less
@@ -132,6 +132,12 @@
text-align: left;
}
}
+
+ .prompt-tip {
+ fill: #aeaeae;
+ margin-left: 8px;
+ line-height: 30px;
+ }
}
&-title {
diff --git a/packages/vue-hooks/README.md b/packages/vue-hooks/README.md
new file mode 100644
index 000000000..6678a527a
--- /dev/null
+++ b/packages/vue-hooks/README.md
@@ -0,0 +1,3 @@
+# @opentiny/vue-hooks
+
+The `usehooks` collection provided by the `TinyVue` component library provides rich combined functions.
diff --git a/packages/vue-hooks/README.zh-CN.md b/packages/vue-hooks/README.zh-CN.md
new file mode 100644
index 000000000..ecb74ccf0
--- /dev/null
+++ b/packages/vue-hooks/README.zh-CN.md
@@ -0,0 +1,3 @@
+# @opentiny/vue-hooks
+
+`TinyVue` 组件库提供的 `usehooks` 集合,提供丰富的组合式函数。
diff --git a/packages/vue-hooks/index.ts b/packages/vue-hooks/index.ts
new file mode 100644
index 000000000..c09400420
--- /dev/null
+++ b/packages/vue-hooks/index.ts
@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) 2022 - present TinyVue Authors.
+ * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
+ *
+ * Use of this source code is governed by an MIT-style license.
+ *
+ * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
+ * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
+ * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
+ *
+ */
+
+import { useFloating } from './src/use-floating'
+
+export { useFloating }
diff --git a/packages/vue-hooks/package.json b/packages/vue-hooks/package.json
new file mode 100644
index 000000000..739b37ec8
--- /dev/null
+++ b/packages/vue-hooks/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@opentiny/vue-hooks",
+ "version": "3.18.0",
+ "description": "",
+ "module": "index.ts",
+ "main": "index.ts",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "dependencies": {
+ "@floating-ui/dom": "^1.6.9",
+ "@opentiny/vue-common": "workspace:~"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
+}
\ No newline at end of file
diff --git a/packages/vue-hooks/src/use-floating.ts b/packages/vue-hooks/src/use-floating.ts
new file mode 100644
index 000000000..e87405710
--- /dev/null
+++ b/packages/vue-hooks/src/use-floating.ts
@@ -0,0 +1,411 @@
+import type { Placement, Strategy, OffsetOptions, RootBoundary, Boundary, ReferenceElement } from '@floating-ui/dom'
+import { computePosition, autoUpdate, flip, offset, shift, arrow, hide, limitShift } from '@floating-ui/dom'
+
+import { hooks } from '@opentiny/vue-common'
+
+const { reactive, watch, markRaw, onBeforeUnmount } = hooks
+
+interface IFloatOption {
+ reference: null | ReferenceElement
+ popper: null | HTMLElement
+ /** ✅ 是否弹出 */
+ show: boolean
+ /** ✅ 是否自动更新位置 */
+ autoUpdate: boolean // 更新策略有5种,4种默认为true。 就依默认策略进行update
+ /** ✅ 弹出层定位策略, 【不建议修改】: 'absolute' | 'fixed' https://floating-ui.com/docs/computePosition#strategy */
+ strategy: Strategy
+ /** ✅ 默认出现的12个位置 */
+ placement: Placement
+ /** ✅ 弹出层偏移量 支持 number | {mainAxis,crossAxis,alignmentAxis}
+ * 1、只传入 number, 代表主轴上的偏移。
+ * 2、crossAxis,alignmentAxis 都是副轴上的偏移, 区别是:
+ * crossAxis 固定向副轴的正方向偏移;
+ * alignmentAxis 在副轴上,根据placement的后段决定偏移。
+ * 比如 top的副轴为水平方向。 指定alignmentAxis=20的话, top-start时,向右20, top-end时 向左20。
+ */
+ offset: OffsetOptions
+ /** ✅ 是否显示箭头 */
+ arrowVisible: boolean
+ /** ✅ 溢出的根边界, 取值为: viewport: 可视视口 document: 整个文档区域 或 自定义Rect:{ x,y,width,height} 【不建议切换,不太确定它影响哪些场景】
+ * 在floating 内部, 计算所有 [...clippingAncestors, rootBoundary] 的rect 大小
+ * 'viewport' 时,访问的是 window.visualViewport, 其 width是不带滚动条的宽度。
+ */
+ rootBoundary: RootBoundary
+ /** ✅ 裁剪元素或区域元素。 默认为最近的rel元素。 此处可自定义为某个元素或Rect */
+ boundary: Boundary
+ /** ✅ 边界预留padding. 设置后,flip 快到边界时,提前就翻转 */
+ boundaryPadding: number
+ /** ✅ 引用元素不可见时,是否自动隐藏。 【需要启用autoUpdate】 */
+ syncHide: boolean
+ /** ✅ 元素弹出后,任何重新定位都自动关闭popper, 适用于右键菜单打开后,滚动就或日期组件在滚动时自动关闭。 【需要启用autoUpdate】 */
+ autoHide: boolean
+ /** ✅ 是否加速。 加速时,绑定popper的translate属性,否则绑定left/top。 【该属性不建议切换】 */
+ gpuAcceleration: boolean
+ /** ✅ 是否动画。 动画的机制简化, 不考虑前个动画未结束时,就开始下个动画的情况。 */
+ animate: boolean
+ /** ✅ 动画类名 */
+ animateName: string
+ /** ✅ 是否添加到body。【该属性不建议切换】
+ * true时, 显示popper时,才body.append; 隐藏时popper.remove。 boundary为 body.
+ * false时, 显示popper, 修改style.display='block', 隐藏修改 display:none boundary为 最近的relative元素 */
+ appendToBody: boolean
+ /** ✅ 自定义类名,以支持不同的主题色, is-dark is-light 等 , 支持空格分隔的多个类名 */
+ customClass: string
+
+ /** 是否启用flip flip, shift 属性会影响弹层的位置。 在鼠标右击菜单等场景,想固定弹出位置时,可以关闭该属性 */
+ flipAble: boolean
+ /** 是否启用shift */
+ shiftAble: boolean
+
+ /** 缓存上次的值。 由于watch state时,取不到oldState的值,所以每次应用后,记录一下 */
+ _last: Partial & {
+ arrowInserted?: boolean
+ arrowEl: HTMLElement
+ timestamp: number
+ }
+ /** 缓存用户注册事件
+ * show 事件:如果useFloating时,show=true, 那么监听不到第一次show事件。 因为第一次show事件在usFloating内部就已经触发了
+ * hide 事件:在动画结束后触发。【是否增加hiding 事件?】
+ * update 事件: 每次定位完后触发。 该事件触发频繁,已观察到有以下情况:
+ * 在 autoUpdate 时,会频繁触发。 比如切换显示,elementResize /IntersectionObserver 事件发生,内部会进入2次
+ * 在reference 不可见时,每一秒会触发一次 update
+ * */
+ _events: { show: Function[]; hide: Function[]; update: Function[] }
+}
+
+/** 默认配置 */
+const defaultOption: Partial = {
+ reference: null,
+ popper: null,
+ show: false,
+ autoUpdate: true,
+
+ strategy: 'absolute',
+ placement: 'bottom',
+ offset: 6,
+ arrowVisible: true,
+ rootBoundary: 'viewport',
+ boundary: 'clippingAncestors',
+ boundaryPadding: 5,
+ syncHide: true,
+ autoHide: false,
+ gpuAcceleration: false,
+ animate: true,
+ animateName: 'fade-in-linear',
+ appendToBody: false,
+ customClass: '',
+
+ flipAble: true,
+ shiftAble: true
+}
+
+const oppositeSidesMap = { top: 'bottom', right: 'left', bottom: 'top', left: 'right' }
+
+const toMs = (s: string) => {
+ if (s === 'auto') return 0
+ return Number(s.slice(0, -1).replace(',', '.')) * 1000
+}
+
+/** 获取元素的当前动画时长,参考 Vue的Transition 的源码实现。 注:无论css中单位是 ms/s, getComputedStyle返回的单位都是 s */
+const getTransitionInfo = (el: HTMLElement) => {
+ const styles = window.getComputedStyle(el)
+ // 先判断transition
+ let timeout = toMs(styles.transitionDelay) + toMs(styles.transitionDuration)
+ if (timeout) return timeout
+
+ // 再判断 animation
+ timeout = toMs(styles.animationDelay) + toMs(styles.animationDuration)
+ if (timeout) return timeout
+
+ return 0
+}
+
+/** 包含多个类名的字符串赋值给元素的classList */
+const applyClass = (el: HTMLElement, classes: string, force: boolean) => {
+ classes.split(' ').forEach((c) => c && el.classList.toggle(c, force))
+}
+
+/** 执行一次 popper 的更新动作 */
+const updatePopper = (state: IFloatOption) => {
+ // 官方建议offset居首, flip在shift前。 arrow,hide居后。
+ const middleware = [offset(state.offset)]
+ state.flipAble &&
+ middleware.push(
+ flip({
+ rootBoundary: state.rootBoundary,
+ boundary: state.boundary,
+ padding: state.boundaryPadding
+ })
+ )
+ state.shiftAble && middleware.push(shift({ limiter: limitShift() }))
+ state.arrowVisible &&
+ middleware.push(
+ arrow({
+ element: state.popper!.querySelector('.tiny-popper__arrow')!,
+ padding: 8
+ })
+ )
+ middleware.push(hide())
+
+ computePosition(state.reference!, state.popper!, {
+ placement: state.placement,
+ strategy: state.strategy,
+ middleware
+ }).then(({ x, y, placement, strategy, middlewareData }) => {
+ // 自动关闭: 如果已经打开状态了,则本次重新定位,则关闭
+ if (state.autoHide && state._last.show) {
+ const timestamp = new Date().getTime()
+ if (timestamp > state._last.timestamp + 300) {
+ state.show = false
+ return
+ }
+ }
+ // 最终绑定给popper的样式
+ const finalStyles: Record = {}
+
+ // 定位策略
+ Object.assign(finalStyles, {
+ position: strategy
+ })
+
+ // 位置:是否加速
+ if (state.gpuAcceleration) {
+ Object.assign(finalStyles, {
+ transform: `translate(${x}px,${y}px)`,
+ left: '0',
+ top: '0'
+ })
+ } else {
+ Object.assign(finalStyles, {
+ left: `${x}px`,
+ top: `${y}px`
+ })
+ }
+
+ // 是否hide
+ if (state.syncHide) {
+ if (middlewareData.hide) {
+ Object.assign(finalStyles, {
+ visibility: middlewareData.hide.referenceHidden ? 'hidden' : 'visible'
+ })
+ }
+ }
+
+ // 应用样式
+ Object.assign(state.popper!.style, finalStyles)
+
+ // 应用customClass
+ if (state._last.customClass && state._last.customClass !== state.customClass) {
+ applyClass(state.popper!, state._last.customClass, false)
+ }
+ if (state.customClass && state._last?.customClass !== state.customClass) {
+ applyClass(state.popper!, state.customClass, true)
+ state._last.customClass = state.customClass
+ }
+
+ // 应用箭头
+ if (state.arrowVisible) {
+ const { x: arrowX, y: arrowY } = middlewareData.arrow
+ const arrowElement = state._last.arrowEl!
+ const staticSide = oppositeSidesMap[placement.split('-')[0]]
+
+ const arrowStyle = {
+ left: arrowX !== null ? `${arrowX}px` : '',
+ top: arrowY !== null ? `${arrowY}px` : '',
+ right: '',
+ bottom: '',
+ [staticSide]: '-4px',
+ display: 'block'
+ }
+ Object.assign(arrowElement.style, arrowStyle)
+ } else {
+ if (state._last!.arrowInserted) {
+ state._last!.arrowEl.style.display = 'none'
+ }
+ }
+
+ // 触发更新事件
+ emit(state, 'update', { x, y, placement, strategy, middlewareData })
+ })
+}
+
+/** 执行自动更新 */
+const autoUpdatePopper = (state: IFloatOption) => {
+ return autoUpdate(state.reference!, state.popper!, () => {
+ updatePopper(state)
+ })
+}
+
+/** popper 插入body,或修改 display 可见。 */
+const appendPopper = (state: IFloatOption) => {
+ // 如果已经打开了,且popper没变化,则忽略
+ if (state._last.show && state._last.popper === state.popper) return
+
+ // 如果popper 变化了, 需要先移除_last.popper。
+ if (state._last.popper && state._last.popper !== state.popper) {
+ if (state._last.appendToBody) {
+ state._last.popper.remove()
+ } else {
+ state._last.popper.style.display = 'none'
+ }
+ state._last.arrowInserted = false
+ state._last.arrowEl = null as unknown as HTMLElement
+ }
+
+ if (state.popper) {
+ // 1、插入元素
+ if (state.appendToBody) {
+ document.body.append(state.popper)
+ } else {
+ state.popper.style.display = 'block'
+ }
+
+ // 2、始终插入箭头元素,update时控制箭头的显隐。(如果不插入,只动态修改arrowVisible,进入不了appendPopper)
+ if (!state._last!.arrowInserted) {
+ const arrowEl = document.createElement('div')
+ arrowEl.className = 'tiny-popper__arrow'
+ state.popper.append(arrowEl)
+
+ state._last!.arrowInserted = true
+ state._last!.arrowEl = arrowEl
+ }
+
+ // 3、 添加动画类
+ if (state.animate) {
+ const enterName = `${state.animateName}-enter-from`
+ const activeName = `${state.animateName}-enter-active`
+ state.popper.classList.add(enterName, activeName)
+ setTimeout(() => {
+ state.popper!.classList.remove(enterName)
+ }, 0)
+ const timeout = getTransitionInfo(state.popper)
+ setTimeout(() => {
+ state.popper!.classList.remove(activeName)
+ }, timeout)
+ }
+
+ // 4、触发事件
+ emit(state, 'show')
+ }
+}
+
+/** popper 移除body,或修改 display 不可见 */
+const closePopper = (state: IFloatOption) => {
+ // 如果已经关闭了,则忽略
+ if (!state._last.show) return
+
+ if (state.popper) {
+ // 如果有动画,动画结束后再移除
+ if (state.animate && state.animateName) {
+ const leaveName = `${state.animateName}-leave-to`
+ const activeName = `${state.animateName}-leave-active`
+
+ state.popper.classList.add(leaveName, activeName)
+ const timeout = getTransitionInfo(state.popper)
+ setTimeout(() => {
+ state.popper!.classList.remove(leaveName, activeName)
+
+ if (state.appendToBody) {
+ state.popper!.remove()
+ } else {
+ state.popper!.style.display = 'none'
+ }
+ emit(state, 'hide')
+ }, timeout)
+ } else {
+ // 否则直接移除
+ if (state.appendToBody) {
+ state.popper.remove()
+ } else {
+ state.popper.style.display = 'none'
+ }
+ emit(state, 'hide')
+ }
+ }
+}
+
+/** 触发事件 */
+const emit = (state: IFloatOption, eventName: string, params?: any) => {
+ state._events[eventName].forEach((cb) => cb(params))
+}
+
+/** 快速构建虚拟元素的辅助方法, 适于右键菜单,区域选择, 跟随光标等场景 */
+const virtualEl = (x: number, y: number, w: number = 0, h: number = 0) => ({
+ getBoundingClientRect() {
+ return {
+ width: 0,
+ height: 0,
+ x,
+ y,
+ top: y,
+ left: x,
+ right: x + w,
+ bottom: y + h
+ }
+ }
+})
+
+/** 响应式的弹出层管理函数,适用于场景: tooltip, poppover, select, 右键菜单, floatbar, notify, 或 canvas上跟随鼠标等 */
+export const useFloating = (option: Partial = {}) => {
+ const state = reactive(option) as IFloatOption
+
+ let cleanup: null | (() => void) = null
+
+ // 0、标准化state
+ Object.keys(defaultOption).forEach((key) => {
+ if (!Object.prototype.hasOwnProperty.call(state, key)) {
+ state[key] = defaultOption[key]
+ }
+ })
+ state._last = markRaw({}) as any
+ state._events = markRaw({ show: [], hide: [], update: [] })
+
+ const watchState = () => {
+ // 1、引用和弹窗同时存在
+ if (state.popper && state.reference) {
+ // 1.1 当前需要显示, 可能是show变化了,也可能是其它任意值变化了, 都需要重新的一次update
+ if (state.show) {
+ appendPopper(state)
+ if (state.autoUpdate) {
+ cleanup && cleanup()
+ cleanup = autoUpdatePopper(state)
+ } else {
+ updatePopper(state)
+ }
+ }
+ // 1.2 当前不需要显示
+ else {
+ cleanup && cleanup()
+ closePopper(state)
+ }
+ }
+ // 2、引用和弹窗不全。 可能前一次是全的,所以要释放一下
+ else {
+ cleanup && cleanup()
+ closePopper(state)
+ }
+
+ state._last.popper = state.popper
+ state._last.reference = state.reference
+ state._last.show = (state.show && state.popper && state.reference) as boolean // 真实的是否show变量
+ state._last.appendToBody = state.appendToBody
+ state._last.timestamp = new Date().getTime()
+ }
+
+ watch(state, watchState, { immediate: true })
+
+ const on = (eventName, cb) => state._events[eventName].push(cb)
+ const off = (eventName, cb) => (state._events[eventName] = state._events[eventName].filter((i) => i !== cb))
+
+ // 3、组件卸载前,移除元素
+ onBeforeUnmount(() => {
+ cleanup && cleanup()
+ closePopper(state)
+ })
+
+ // 4、返回state 及辅助方法
+ // 正常修改state去触发更新,但如果某些业务想在state不变时,仍想执行一次更新, 则使用forceUpdate即可
+ // 比如select 懒加载: popper, show都不变, 但popper 的大小变化了,可以forceUpdate一下。
+ // 【autoUpdate 理论上会监听 popper的resize的, 这层考虑可能是多余。】
+ return { state, on, off, virtualEl, forceUpdate: watchState }
+}
diff --git a/packages/vue-locale/src/lang/en.ts b/packages/vue-locale/src/lang/en.ts
index 18d56f3a1..335813863 100644
--- a/packages/vue-locale/src/lang/en.ts
+++ b/packages/vue-locale/src/lang/en.ts
@@ -289,7 +289,7 @@ export default {
calcHash: 'Document is calculating encryption',
uploadFile: 'Upload file',
downloadAll: 'Download all',
- onlySupport: 'Only support {type} file',
+ onlySupport: 'Support {type} file',
fileNotLessThan: 'The size of single file cannot be less than ',
fileNotMoreThan: 'The size of single file cannot be more than ',
fileSizeRange: 'The size of a single file must range from {moreThan} to {lessThan}.',
diff --git a/packages/vue-locale/src/lang/zh-CN.ts b/packages/vue-locale/src/lang/zh-CN.ts
index c2bee7c06..6f101f913 100644
--- a/packages/vue-locale/src/lang/zh-CN.ts
+++ b/packages/vue-locale/src/lang/zh-CN.ts
@@ -291,7 +291,7 @@ export default {
calcHash: '文档正在计算加密中',
uploadFile: '文件上传',
downloadAll: '全部下载',
- onlySupport: '仅支持{type}格式文件',
+ onlySupport: '支持{type}格式文件',
fileNotLessThan: '单个文件不能小于',
fileNotMoreThan: '单个文件不能超过',
fileSizeRange: '单个文件大小需在{moreThan}~{lessThan}之间',
diff --git a/packages/vue/src/date-panel/src/index.ts b/packages/vue/src/date-panel/src/index.ts
index 478dfd572..fdcd17e39 100644
--- a/packages/vue/src/date-panel/src/index.ts
+++ b/packages/vue/src/date-panel/src/index.ts
@@ -17,7 +17,10 @@ export default defineComponent({
type: Boolean,
default: false
},
- formatWeeks: Function
+ formatWeeks: Function,
+ nowClick: {
+ type: Function
+ }
},
setup(props, context) {
return $setup({ props, context, template })
diff --git a/packages/vue/src/date-panel/src/mobile-first.vue b/packages/vue/src/date-panel/src/mobile-first.vue
index 6164c2174..ba9c5593c 100644
--- a/packages/vue/src/date-panel/src/mobile-first.vue
+++ b/packages/vue/src/date-panel/src/mobile-first.vue
@@ -206,16 +206,18 @@
-
- {{ t('ui.datepicker.now') }}
-
+
+
+ {{ t('ui.datepicker.now') }}
+
+
)}
{state.currentBreakpoint !== 'default' && (
-
+
-
+ {promptTip && tipMessage && (
+
+
+
+ )}
+ {!promptTip && tipMessage && (
+
+ {tipMessage}
+
+ )}
+
)}
{operateSlot}
= limit
@@ -106,6 +107,7 @@ export default defineComponent({
)}
{operateSlot}
+ {tipSlot}