diff --git a/examples/sites/demos/apis/dialog-box.js b/examples/sites/demos/apis/dialog-box.js index 5442b4250..8150a4124 100644 --- a/examples/sites/demos/apis/dialog-box.js +++ b/examples/sites/demos/apis/dialog-box.js @@ -246,6 +246,36 @@ export default { mode: ['pc'], pcDemo: 'dialog-width' }, + { + name: 'custom-style', + type: 'string', + defaultValue: ``, + desc: { + 'zh-CN': '自定义实现双层抽屉', + 'en-US': 'Custom Styles' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc', 'mobile-first'], + pcDemo: 'double-dialog-height', + mfDemo: 'double-dialog-height' + }, + { + name: 'no-animation', + type: 'string', + defaultValue: ``, + desc: { + 'zh-CN': '是否开启动画', + 'en-US': 'Indicates whether to enable animation' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc', 'mobile-first'], + pcDemo: 'double-dialog-height', + mfDemo: 'double-dialog-height' + }, { name: 'dialog-transition', type: 'string', diff --git a/examples/sites/demos/apis/divider.js b/examples/sites/demos/apis/divider.js index 885cfdca9..400c2513d 100644 --- a/examples/sites/demos/apis/divider.js +++ b/examples/sites/demos/apis/divider.js @@ -10,11 +10,13 @@ export default { type: 'string', defaultValue: "'solid'", desc: { - 'zh-CN': '设置分隔线的样式,该属性的可选值为 solid / dashed', - 'en-US': 'Set the style of the separator line, with optional values of solid/dashed for this property' + 'zh-CN': '设置分隔线的样式,该属性的可选值为 solid / dashed / dotted', + 'en-US': + 'Set the style of the separator line, with optional values of solid/dashed/dotted for this property' }, - mode: ['pc'], - pcDemo: 'custom-style' + mode: ['pc', 'mobile-first'], + pcDemo: 'custom-style', + mfDemo: 'type' }, { name: 'color', @@ -24,8 +26,9 @@ export default { 'zh-CN': '设置分隔线的颜色', 'en-US': 'Set the color of the divider.' }, - mode: ['pc'], - pcDemo: 'custom-style' + mode: ['pc', 'mobile-first'], + pcDemo: 'custom-style', + mfDemo: 'color' }, { name: 'content-background-color', @@ -58,8 +61,9 @@ export default { 'en-US': 'Set the position of the separator text, with optional values of left/center/right for this attribute' }, - mode: ['pc'], - pcDemo: 'content-position' + mode: ['pc', 'mobile-first'], + pcDemo: 'content-position', + mfDemo: 'content-position' }, { name: 'direction', @@ -70,8 +74,83 @@ export default { 'en-US': 'Set the direction of the divider; the possible values for this property are "horizontal" or "vertical"' }, + mode: ['pc', 'mobile-first'], + pcDemo: 'direction', + mfDemo: 'vertical' + }, + { + name: 'margin', + type: 'string', + defaultValue: '', + desc: { + 'zh-CN': '设置分割线上下左右的边距', + 'en-US': 'Sets the margins of the split line' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc', 'mobile-first'], + pcDemo: 'custom-style', + mfDemo: 'divider-margin' + }, + { + name: 'offset', + type: 'string', + defaultValue: '', + desc: { + 'zh-CN': '设置文本位置偏移量,需同时配合`text-position`属性使用,以确定偏移的方向', + 'en-US': + 'Sets the text position offset. This parameter must be used together with the `text-position` attribute to determine the offset direction' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc', 'mobile-first'], + pcDemo: 'content-position', + mfDemo: 'offset' + }, + { + name: 'height', + type: 'string', + defaultValue: '', + desc: { + 'zh-CN': '设置整体的高度', + 'en-US': 'Sets the overall height' + }, + meta: { + stable: '3.21.0' + }, mode: ['pc'], - pcDemo: 'direction' + pcDemo: 'custom-style' + }, + { + name: 'font-size', + type: 'string', + defaultValue: '14px', + desc: { + 'zh-CN': '文本字体大小', + 'en-US': 'Text font size' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc'], + pcDemo: 'custom-style' + }, + { + name: 'status', + type: 'string', + defaultValue: '', + desc: { + 'zh-CN': '分割线状态', + 'en-US': 'Splitting Line Status' + }, + meta: { + stable: '3.21.0' + }, + mode: ['pc', 'mobile-first'], + pcDemo: 'status', + mfDemo: 'status' } ], events: [], diff --git a/examples/sites/demos/apis/form.js b/examples/sites/demos/apis/form.js index 604f36723..d7ecb659d 100644 --- a/examples/sites/demos/apis/form.js +++ b/examples/sites/demos/apis/form.js @@ -219,10 +219,10 @@ export default { }, { name: 'validate-on-rule-change', - type: 'boolean', + type: 'boolean | "deep"', defaultValue: 'true', desc: { - 'zh-CN': '是否在 rules 属性改变后立即触发一次验证', + 'zh-CN': '是否在 rules 属性改变后立即触发一次验证("deep"选项新增于3.21.0)', 'en-US': 'Whether to trigger a verification immediately after the rules attribute is changed' }, mode: ['pc', 'mobile', 'mobile-first'], diff --git a/examples/sites/demos/mobile-first/app/dialog-box/double-dialog-height.vue b/examples/sites/demos/mobile-first/app/dialog-box/double-dialog-height.vue new file mode 100644 index 000000000..cd894bf2f --- /dev/null +++ b/examples/sites/demos/mobile-first/app/dialog-box/double-dialog-height.vue @@ -0,0 +1,128 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/dialog-box/webdoc/dialog-box.js b/examples/sites/demos/mobile-first/app/dialog-box/webdoc/dialog-box.js index 1c6225931..9f824b7ef 100644 --- a/examples/sites/demos/mobile-first/app/dialog-box/webdoc/dialog-box.js +++ b/examples/sites/demos/mobile-first/app/dialog-box/webdoc/dialog-box.js @@ -82,6 +82,19 @@ export default { 'en-US': '

code>default: content default slot. footer: bottom slot

' }, codeFiles: ['dialog-slot.vue'] + }, + { + demoId: 'double-dialog-height', + name: { + 'zh-CN': '右侧双层弹框', + 'en-US': 'Double-layer dialog box on the right' + }, + desc: { + 'zh-CN': '右侧弹窗分两种情况,父级弹框自动缩进,子级弹框高度撑满。父级弹框不缩进,子级弹框高度自适应。', + 'en-US': + 'There are two types of pop-up windows on the right. The parent pop-up boxes are automatically indented, and the child pop-up boxes are full. The parent dialog box is not indented, and the height of the child dialog box is adaptive.' + }, + codeFiles: ['double-dialog-height.vue'] } ] } diff --git a/examples/sites/demos/mobile-first/app/divider/basic-usage.vue b/examples/sites/demos/mobile-first/app/divider/basic-usage.vue new file mode 100644 index 000000000..543466b71 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/basic-usage.vue @@ -0,0 +1,19 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/color.vue b/examples/sites/demos/mobile-first/app/divider/color.vue new file mode 100644 index 000000000..c9ee5b04f --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/color.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/content-position.vue b/examples/sites/demos/mobile-first/app/divider/content-position.vue new file mode 100644 index 000000000..f7a846ff4 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/content-position.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/divider-margin.vue b/examples/sites/demos/mobile-first/app/divider/divider-margin.vue new file mode 100644 index 000000000..815cd4a13 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/divider-margin.vue @@ -0,0 +1,19 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/offset.vue b/examples/sites/demos/mobile-first/app/divider/offset.vue new file mode 100644 index 000000000..8b7a2cc17 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/offset.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/status.vue b/examples/sites/demos/mobile-first/app/divider/status.vue new file mode 100644 index 000000000..176b90999 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/status.vue @@ -0,0 +1,19 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/type.vue b/examples/sites/demos/mobile-first/app/divider/type.vue new file mode 100644 index 000000000..9024c60d3 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/type.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/vertical.vue b/examples/sites/demos/mobile-first/app/divider/vertical.vue new file mode 100644 index 000000000..651d9539a --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/vertical.vue @@ -0,0 +1,34 @@ + + + diff --git a/examples/sites/demos/mobile-first/app/divider/webdoc/divider.cn.md b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.cn.md new file mode 100644 index 000000000..dcde68c70 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.cn.md @@ -0,0 +1,7 @@ +--- +title: Divider 分割线 +--- + +# Divider 分割线 + +
Divider 分割线组件,用于对不同内容的分隔。
diff --git a/examples/sites/demos/mobile-first/app/divider/webdoc/divider.en.md b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.en.md new file mode 100644 index 000000000..75a5912ac --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.en.md @@ -0,0 +1,7 @@ +--- +title: Divider split line +--- + +# Divider split line + +
Divider Splitting line component, which is used to separate different contents.
diff --git a/examples/sites/demos/mobile-first/app/divider/webdoc/divider.js b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.js new file mode 100644 index 000000000..df2bc1fc3 --- /dev/null +++ b/examples/sites/demos/mobile-first/app/divider/webdoc/divider.js @@ -0,0 +1,111 @@ +export default { + column: '2', + owner: '', + demos: [ + { + demoId: 'basic-usage', + name: { + 'zh-CN': '基本用法', + 'en-US': 'Basic Usage' + }, + desc: { + 'zh-CN': '带文本的分割线', + 'en-US': 'Splitting line with text' + }, + codeFiles: ['basic-usage.vue'] + }, + { + demoId: 'divider-margin', + name: { + 'zh-CN': '边距用法', + 'en-US': 'Margin Usage' + }, + desc: { + 'zh-CN': '通过margin属性可以设置分割线上下左右的边距。', + 'en-US': 'You can use the margin attribute to set the margins of the split line.' + }, + codeFiles: ['divider-margin.vue'] + }, + { + demoId: 'color', + name: { + 'zh-CN': '颜色用法', + 'en-US': 'Color Usage' + }, + desc: { + 'zh-CN': '通过color属性可以自定义分割线颜色。', + 'en-US': 'You can use the color attribute to customize the color of the split line.' + }, + codeFiles: ['color.vue'] + }, + { + demoId: 'offset', + name: { + 'zh-CN': '偏移量用法', + 'en-US': 'Offset Usage' + }, + desc: { + 'zh-CN': + '通过offset属性可以设置文本位置偏移量,需同时配合content-position属性使用,以确定偏移的方向。', + 'en-US': + 'offset can be used to set the text position offset. It must be used together with the content-position attribute to determine the offset direction.' + }, + codeFiles: ['offset.vue'] + }, + { + demoId: 'type', + name: { + 'zh-CN': '分割线类型', + 'en-US': 'Type Usage' + }, + desc: { + 'zh-CN': + '通过border-style属性可以设置分割线类型,可选值有soliddasheddotted,默认为solid。', + 'en-US': + 'You can set the split line type through the border-style attribute. The options are soliddasheddotted. The default value is solid.' + }, + codeFiles: ['type.vue'] + }, + { + demoId: 'content-position', + name: { + 'zh-CN': '文本位置用法', + 'en-US': 'Text Position' + }, + desc: { + 'zh-CN': + '通过content-position属性可以设置分割线文本位置,可选值有centerleftright三种,默认为center。', + 'en-US': + 'You can use the content-position attribute to set the text position of the split line. The options are as follows: centerleftright. The default value is center.' + }, + codeFiles: ['content-position.vue'] + }, + { + demoId: 'status', + name: { + 'zh-CN': '状态', + 'en-US': 'Status' + }, + desc: { + 'zh-CN': + '通过status属性可以设置分割线状态,可选值有defaultsuccesswarningerrorinfo五种状态。', + 'en-US': + 'You can use the status attribute to set the split line status. The options are defaultsuccesswarningerrorinfo.' + }, + codeFiles: ['status.vue'] + }, + { + demoId: 'vertical', + name: { + 'zh-CN': '垂直方向', + 'en-US': 'Vertical direction' + }, + desc: { + 'zh-CN': '通过direction属性设置为vertical,垂直分割线,不支持默认插槽。', + 'en-US': + 'Set the direction attribute to vertical, which indicates a vertical split line. The default slot is not supported.' + }, + codeFiles: ['vertical.vue'] + } + ] +} diff --git a/examples/sites/demos/mobile-first/menus.js b/examples/sites/demos/mobile-first/menus.js index 8a8f08801..91b112517 100644 --- a/examples/sites/demos/mobile-first/menus.js +++ b/examples/sites/demos/mobile-first/menus.js @@ -125,7 +125,8 @@ export const cmpMenus = [ { name: 'Amount', nameCn: '金额', key: 'amount' }, { name: 'currency', nameCn: '币种', key: 'currency' }, { name: 'CalendarView', nameCn: '日历', key: 'calendar-view' }, - { name: 'FloatingButton', nameCn: '悬浮按钮', key: 'floating-button' } + { name: 'FloatingButton', nameCn: '悬浮按钮', key: 'floating-button' }, + { name: 'Divider', nameCn: '分割线', key: 'divider' } ] } ] diff --git a/examples/sites/demos/pc/app/date-picker/disabled-composition-api.vue b/examples/sites/demos/pc/app/date-picker/disabled-composition-api.vue index 60520d8d7..2d3784a32 100644 --- a/examples/sites/demos/pc/app/date-picker/disabled-composition-api.vue +++ b/examples/sites/demos/pc/app/date-picker/disabled-composition-api.vue @@ -58,7 +58,7 @@ const pickerOptions = { } const yearPickerOptions = { disabledDate(year) { - return year > 2025 || year < 2022 + return year.getTime() > new Date(2025, 0, 1, 0).getTime() || year.getTime() < new Date(2022, 0, 1, 0).getTime() } } diff --git a/examples/sites/demos/pc/app/date-picker/disabled.vue b/examples/sites/demos/pc/app/date-picker/disabled.vue index 4073d563b..4cbbf677b 100644 --- a/examples/sites/demos/pc/app/date-picker/disabled.vue +++ b/examples/sites/demos/pc/app/date-picker/disabled.vue @@ -62,7 +62,9 @@ export default { }, yearPickerOptions: { disabledDate(year) { - return year > 2025 || year < 2022 + return ( + year.getTime() > new Date(2025, 0, 1, 0).getTime() || year.getTime() < new Date(2022, 0, 1, 0).getTime() + ) } } } diff --git a/examples/sites/demos/pc/app/dialog-box/double-dialog-height-composition-api.vue b/examples/sites/demos/pc/app/dialog-box/double-dialog-height-composition-api.vue new file mode 100644 index 000000000..041f8d591 --- /dev/null +++ b/examples/sites/demos/pc/app/dialog-box/double-dialog-height-composition-api.vue @@ -0,0 +1,129 @@ + + + diff --git a/examples/sites/demos/pc/app/dialog-box/double-dialog-height.vue b/examples/sites/demos/pc/app/dialog-box/double-dialog-height.vue new file mode 100644 index 000000000..cd894bf2f --- /dev/null +++ b/examples/sites/demos/pc/app/dialog-box/double-dialog-height.vue @@ -0,0 +1,128 @@ + + + diff --git a/examples/sites/demos/pc/app/dialog-box/webdoc/dialog-box.js b/examples/sites/demos/pc/app/dialog-box/webdoc/dialog-box.js index dffee806c..4432a024b 100644 --- a/examples/sites/demos/pc/app/dialog-box/webdoc/dialog-box.js +++ b/examples/sites/demos/pc/app/dialog-box/webdoc/dialog-box.js @@ -164,6 +164,19 @@ export default { }, codeFiles: ['right-dialog.vue'] }, + { + demoId: 'double-dialog-height', + name: { + 'zh-CN': '右侧双层弹框', + 'en-US': 'Double-layer dialog box on the right' + }, + desc: { + 'zh-CN': '右侧弹窗分两种情况,父级弹框自动缩进,子级弹框高度撑满。父级弹框不缩进,子级弹框高度自适应。', + 'en-US': + 'There are two types of pop-up windows on the right. The parent pop-up boxes are automatically indented, and the child pop-up boxes are full. The parent dialog box is not indented, and the height of the child dialog box is adaptive.' + }, + codeFiles: ['double-dialog-height.vue'] + }, { demoId: 'hidden-header', name: { diff --git a/examples/sites/demos/pc/app/divider/base-composition-api.vue b/examples/sites/demos/pc/app/divider/basic-usage-composition-api.vue similarity index 100% rename from examples/sites/demos/pc/app/divider/base-composition-api.vue rename to examples/sites/demos/pc/app/divider/basic-usage-composition-api.vue diff --git a/examples/sites/demos/pc/app/divider/basic-usage.spec.ts b/examples/sites/demos/pc/app/divider/basic-usage.spec.ts deleted file mode 100644 index 84df68842..000000000 --- a/examples/sites/demos/pc/app/divider/basic-usage.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { test, expect } from '@playwright/test' - -test('Divider 基础用法', async ({ page }) => { - page.on('pageerror', (exception) => expect(exception).toBeNull()) - await page.goto('divider#basic-usage') - await page.locator('.tiny-divider').click() -}) diff --git a/examples/sites/demos/pc/app/divider/base.vue b/examples/sites/demos/pc/app/divider/basic-usage.vue similarity index 100% rename from examples/sites/demos/pc/app/divider/base.vue rename to examples/sites/demos/pc/app/divider/basic-usage.vue diff --git a/examples/sites/demos/pc/app/divider/content-position-composition-api.vue b/examples/sites/demos/pc/app/divider/content-position-composition-api.vue new file mode 100644 index 000000000..7c3b80c8c --- /dev/null +++ b/examples/sites/demos/pc/app/divider/content-position-composition-api.vue @@ -0,0 +1,14 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/content-position.vue b/examples/sites/demos/pc/app/divider/content-position.vue new file mode 100644 index 000000000..943454558 --- /dev/null +++ b/examples/sites/demos/pc/app/divider/content-position.vue @@ -0,0 +1,20 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/contentPosition-composition-api.vue b/examples/sites/demos/pc/app/divider/contentPosition-composition-api.vue deleted file mode 100644 index bee75d836..000000000 --- a/examples/sites/demos/pc/app/divider/contentPosition-composition-api.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/examples/sites/demos/pc/app/divider/contentPosition.vue b/examples/sites/demos/pc/app/divider/contentPosition.vue deleted file mode 100644 index b0407675e..000000000 --- a/examples/sites/demos/pc/app/divider/contentPosition.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/examples/sites/demos/pc/app/divider/custom-style-composition-api.vue b/examples/sites/demos/pc/app/divider/custom-style-composition-api.vue new file mode 100644 index 000000000..b32082c39 --- /dev/null +++ b/examples/sites/demos/pc/app/divider/custom-style-composition-api.vue @@ -0,0 +1,14 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/custom-style.vue b/examples/sites/demos/pc/app/divider/custom-style.vue new file mode 100644 index 000000000..d4c6e13d5 --- /dev/null +++ b/examples/sites/demos/pc/app/divider/custom-style.vue @@ -0,0 +1,22 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/customStyle-composition-api.vue b/examples/sites/demos/pc/app/divider/customStyle-composition-api.vue deleted file mode 100644 index 060b08c37..000000000 --- a/examples/sites/demos/pc/app/divider/customStyle-composition-api.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/examples/sites/demos/pc/app/divider/customStyle.vue b/examples/sites/demos/pc/app/divider/customStyle.vue deleted file mode 100644 index 21eb07621..000000000 --- a/examples/sites/demos/pc/app/divider/customStyle.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/examples/sites/demos/pc/app/divider/direction-composition-api.vue b/examples/sites/demos/pc/app/divider/direction-composition-api.vue index aba3bf5d3..99506bfbc 100644 --- a/examples/sites/demos/pc/app/divider/direction-composition-api.vue +++ b/examples/sites/demos/pc/app/divider/direction-composition-api.vue @@ -1,9 +1,11 @@ diff --git a/examples/sites/demos/pc/app/divider/divider-type.vue b/examples/sites/demos/pc/app/divider/divider-type.vue new file mode 100644 index 000000000..0da06dbce --- /dev/null +++ b/examples/sites/demos/pc/app/divider/divider-type.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/status-composition-api.vue b/examples/sites/demos/pc/app/divider/status-composition-api.vue new file mode 100644 index 000000000..7ea0652d5 --- /dev/null +++ b/examples/sites/demos/pc/app/divider/status-composition-api.vue @@ -0,0 +1,13 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/status.vue b/examples/sites/demos/pc/app/divider/status.vue new file mode 100644 index 000000000..176b90999 --- /dev/null +++ b/examples/sites/demos/pc/app/divider/status.vue @@ -0,0 +1,19 @@ + + + diff --git a/examples/sites/demos/pc/app/divider/webdoc/divider.js b/examples/sites/demos/pc/app/divider/webdoc/divider.js index 6151be79e..65f445a5f 100644 --- a/examples/sites/demos/pc/app/divider/webdoc/divider.js +++ b/examples/sites/demos/pc/app/divider/webdoc/divider.js @@ -12,7 +12,7 @@ export default { 'zh-CN': '通过引用组件标签即可。', 'en-US': 'You can refer to component label.' }, - codeFiles: ['base.vue'] + codeFiles: ['basic-usage.vue'] }, { demoId: 'direction', @@ -21,8 +21,9 @@ export default { 'en-US': 'Vertical divider line' }, desc: { - 'zh-CN': '

通过 direction 属性可以设置分隔线的方向。

', - 'en-US': '

The direction of the separator line can be set through thedirectionattribute.

' + 'zh-CN': '

通过设置vertical属性为true可以设置分隔线的方向。

', + 'en-US': + '

You can set the direction of the divider by setting the vertical property to true.

' }, codeFiles: ['direction.vue'] }, @@ -33,11 +34,11 @@ export default { 'en-US': 'The position of the separator copy' }, desc: { - 'zh-CN': '

通过 content-position 属性 可以设置分隔线文案的位置。

', + 'zh-CN': '通过text-position 属性设置分隔线文案的位置,offset属性设置左右偏移量。', 'en-US': - '

The position of the separator text can be set through thecontent positionattribute.

' + 'The text-position attribute is used to set the position of the partition line copywriting, and the offset attribute is used to set the left and right offsets.' }, - codeFiles: ['contentPosition.vue'] + codeFiles: ['content-position.vue'] }, { demoId: 'custom-style', @@ -47,11 +48,37 @@ export default { }, desc: { 'zh-CN': - '

通过colorborder-stylecontent-color属性,自定义分割线样式。

', + '通过line-color属性设置分割线颜色,content-background-color属性设置文案背景颜色,content-color属性设置文字颜色,height属性设置分割线整体内容高度,margin属性设置外边距值。', 'en-US': - '

Customize the split line style through thecolorborder stylecontent colorattribute.

' + 'The line-color attribute sets the color of the split line, the content-background-color attribute sets the background color of the copywriting, the content-color attribute sets the text color, and the height Property Sets the overall content height of the split line. The margin property sets the outer margin value.' }, - codeFiles: ['customStyle.vue'] + codeFiles: ['custom-style.vue'] + }, + { + demoId: 'divider-type', + name: { + 'zh-CN': '分隔线类型', + 'en-US': 'Separator Line Type' + }, + desc: { + 'zh-CN': + '通过type设置分割线显示类型,默认值为solid,可选值为dasheddotted。', + 'en-US': + 'Set the display type of the split line through type. The default value is solid. The options are dasheddotted.' + }, + codeFiles: ['divider-type.vue'] + }, + { + demoId: 'status', + name: { + 'zh-CN': '分隔线状态', + 'en-US': 'Separator Status' + }, + desc: { + 'zh-CN': '通过status属性设置分割线显示状态颜色。', + 'en-US': 'Use the status attribute to set the color of the display status of the splitter line.' + }, + codeFiles: ['status.vue'] } ] } diff --git a/internals/cli/src/commands/build/build-ui.ts b/internals/cli/src/commands/build/build-ui.ts index 616b0e9db..8569bd419 100644 --- a/internals/cli/src/commands/build/build-ui.ts +++ b/internals/cli/src/commands/build/build-ui.ts @@ -10,7 +10,7 @@ import { getAlias, pathFromWorkspaceRoot } from '../../config/vite' import { external } from '../../shared/config' import type { Module } from '../../shared/module-utils' import { getAllIcons, getAllModules, getByName } from '../../shared/module-utils' -import { logGreen, kebabCase, capitalizeKebabCase, getPatchVersion, isValidVersion } from '../../shared/utils' +import { capitalizeKebabCase, getPatchVersion, isValidVersion, kebabCase, logGreen } from '../../shared/utils' import generatePackageJsonPlugin from './rollup/generate-package-json' import inlineChunksPlugin from './rollup/inline-chunks' import replaceModuleNamePlugin from './rollup/replace-module-name' @@ -257,11 +257,7 @@ export const getBaseConfig = ({ vueVersion, dtsInclude, dts, buildTarget, isRunt extensions: ['.js', '.ts', '.tsx', '.vue'], alias: { ...getAlias(vueVersion, '', design), - '@tiptap/vue': `${ - vueVersion === '2' - ? path.resolve(pathFromPackages(''), 'vue/src/rich-text-editor/node_modules/@tiptap/vue-2') - : path.resolve(pathFromPackages(''), 'vue/src/rich-text-editor/node_modules/@tiptap/vue-3') - }`, + '@tiptap/vue': `${vueVersion === '2' ? '@tiptap/vue-2' : '@tiptap/vue-3'}`, '@vue/babel-helper-vue-jsx-merge-props': 'node_modules/@vue/babel-helper-vue-jsx-merge-props/dist/helper.js' } }, diff --git a/internals/cli/src/shared/config.ts b/internals/cli/src/shared/config.ts index 8d0ab0cf1..d02636082 100644 --- a/internals/cli/src/shared/config.ts +++ b/internals/cli/src/shared/config.ts @@ -1,3 +1,5 @@ +import rich_text_editor_pkg from '../../../../packages/vue/src/rich-text-editor/package.json' + const EXTENERAL = [ 'vue', 'axios', @@ -9,7 +11,8 @@ const EXTENERAL = [ 'streamsaver', 'shepherd.js', './label-wrap', - './tall-storage.vue' + './tall-storage.vue', + ...Object.keys(rich_text_editor_pkg.peerDependencies) ] const external = (deps) => { return EXTENERAL.includes(deps) || /^@opentiny[\\/]|@originjs|echarts|cropperjs|@better-scroll/.test(deps) diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 76fbc30b8..1189e527a 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -44,4 +44,4 @@ "vite-plugin-dts": "^4.3.0", "vite-svg-loader": "^5.1.0" } -} +} \ No newline at end of file diff --git a/packages/mobile/utils/package.json b/packages/mobile/utils/package.json index 139f712dc..3d3ceedeb 100644 --- a/packages/mobile/utils/package.json +++ b/packages/mobile/utils/package.json @@ -11,4 +11,4 @@ "build": "pnpm -w build:ui", "postversion": "pnpm build" } -} +} \ No newline at end of file diff --git a/packages/mobile/vue-common/src/adapter/vue3/index.ts b/packages/mobile/vue-common/src/adapter/vue3/index.ts new file mode 100644 index 000000000..d7b00f08c --- /dev/null +++ b/packages/mobile/vue-common/src/adapter/vue3/index.ts @@ -0,0 +1,496 @@ +/** + * 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 * as hooks from 'vue' + +import { camelize, capitalize, hyphenate } from '@opentiny/mobile-utils/string' +import { bindFilter, emitter, getElementCssClass, getElementStatusClass } from '../utils' + +const Teleport = hooks.Teleport + +export { emitter, bindFilter, getElementCssClass, getElementStatusClass, Teleport } + +export const defineAsyncComponent = hooks.defineAsyncComponent + +export const markRaw = hooks.markRaw + +export const renderComponent = ({ + view = undefined as any, + component = undefined as any, + props, + context: { attrs, slots }, + extend = {} +}) => { + return () => hooks.h((view && view.value) || component, { ref: 'modeTemplate', ...props, ...attrs, ...extend }, slots) +} + +export const rootConfig = (context) => { + const instance = hooks.getCurrentInstance() + context && setInstanceEmitter(instance) + return instance?.appContext.config.globalProperties +} + +export const getComponentName = () => { + // 此处组件最多为两层组件,所以对多获取到父级组件即可 + const instance = hooks.getCurrentInstance() + let componentName = instance?.type?.name + if (!componentName) { + componentName = instance?.parent?.type?.name + } + + return componentName || '' +} + +export const appContext = () => + hooks.getCurrentInstance()?.appContext || { + component: () => { + // do nothing + } + } + +export const appProperties = () => { + const instance = hooks.getCurrentInstance() + return instance?.appContext.config.globalProperties || {} +} + +export const useRouter = (instance = hooks.getCurrentInstance()) => { + const router = instance?.appContext.config.globalProperties.$router + const route = router && router.currentRoute.value + + return { route, router } +} + +const setInstanceEmitter = (instance) => { + const $emitter = emitter() + + if (typeof instance.$emitter === 'undefined') Object.defineProperty(instance, '$emitter', { get: () => $emitter }) +} + +const emitEvent = (vm) => { + const broadcast = (vm, componentName, eventName, params) => { + const children = (vm.subTree && vm.subTree.children) || vm.children + + Array.isArray(children) && + children.forEach((child) => { + const name = child.type && child.type.componentName + const component = child.component + + if (name === componentName) { + component.emit(eventName, params) + component.$emitter && component.$emitter.emit(eventName, params) + } else { + broadcast(child, componentName, eventName, params) + } + }) + } + + return { + dispatch(componentName, eventName, params) { + let parent = vm.parent || vm.root + let name = parent.type && parent.type.componentName + + while (parent && (!name || name !== componentName)) { + parent = parent.parent + + if (parent) name = parent.type && parent.type.componentName + } + + if (parent) { + parent.emit(...[eventName].concat(params)) + // fix: VUE3下事件参数为数组,VUE2下事件参数不是数组,这里修改为和VUE2兼容 + parent.$emitter && parent.$emitter.emit(...[eventName].concat(params)) + } + }, + broadcast(componentName, eventName, params) { + broadcast(vm, componentName, eventName, params) + } + } +} + +const getRealParent = (vm) => { + if (vm && vm.parent) + return vm.parent.type.name === 'AsyncComponentWrapper' && vm.parent.parent ? vm.parent.parent : vm.parent +} + +const parent = (vm) => (handler) => { + let parent = getRealParent(vm) + let level = 0 + + const parentObject = (parent) => { + return { + level, + vm: createVm({}, parent), + el: parent.vnode.el, + options: parent.type + } + } + + if (typeof handler !== 'function') return parent ? parentObject(parent) : {} + + level++ + + while (parent) { + if (handler(parentObject(parent))) break + parent = getRealParent(parent) + level++ + } +} + +const children = (vm) => (handler) => { + if (typeof handler !== 'function') return generateChildren(vm.subTree) + + let layer = 1 + const broadcast = (subTree) => { + if (subTree) { + const children = subTree.children || subTree.dynamicChildren + const level = layer++ + + if (Array.isArray(children)) { + if ( + children.some((child) => { + return ( + child.component && + handler({ + level, + vm: createVm({}, child.component), + el: child.el, + options: child.type, + isLevel1: true + }) + ) + }) + ) + return + + children.forEach((child) => broadcast(child)) + } + } + } + + broadcast(vm.subTree) +} + +const regEventPrefix = /^on[A-Z]/ + +const generateListeners = (attrs) => { + const $attrs = {} + const $listeners = {} + + for (const name in attrs) { + const event = attrs[name] + + if (regEventPrefix.test(name) && typeof event === 'function') { + $listeners[hyphenate(name.substr(2))] = event + continue + } + + $attrs[name] = event + } + + return { $attrs, $listeners } +} + +const generateChildren = (subTree) => { + const children: any = [] + children.refs = {} + + if (subTree) { + const arr = subTree.dynamicChildren || subTree.children + + if (Array.isArray(arr)) { + arr.forEach((child) => { + if (child.component) { + const vm = createVm({}, child.component) + + children.push(vm) + child.props.ref && (children.refs[child.props.ref] = vm) + } + }) + } else if (subTree.component) { + children.push(createVm({}, subTree.component)) + } + } + + return children +} + +const defineProperties = (vm, instance, property, filter) => { + for (const name in instance[property]) { + if (typeof filter === 'function' && filter(name)) continue + + Object.defineProperty(vm, name, { + configurable: true, + enumerable: true, + get: () => instance[property][name], + set: (value) => (instance[property][name] = value) + }) + } + + return vm +} + +const filter = (name) => name.indexOf('_') === 0 + +const defineInstanceVm = (vm, instance) => { + defineProperties(vm, instance, 'setupState', null) + defineProperties(vm, instance, 'props', filter) + defineProperties(vm, instance, 'ctx', filter) + + return vm +} + +const createVm = (vm, instance, context = null) => { + const { $attrs, $listeners } = generateListeners(instance.attrs) + let $emitter = instance.$emitter + + if (!$emitter) { + setInstanceEmitter(instance) + $emitter = instance.$emitter + } + + const emit = (...args) => { + instance.emit(...args) + $emitter.emit.apply(vm, args) + } + + const $set = (target, propertyName, value) => (target[propertyName] = value) + + context || defineInstanceVm(vm, instance) + + Object.defineProperties(vm, { + $attrs: { get: () => $attrs }, + $children: { get: () => generateChildren(instance.subTree) }, + $constants: { get: () => instance.props._constants }, + $emit: { get: () => emit }, + $el: { get: () => instance.vnode.el }, + $listeners: { get: () => $listeners }, + $mode: { get: () => instance._tiny_mode }, + $nextTick: { get: () => hooks.nextTick }, + $off: { get: () => $emitter.off }, + $on: { get: () => $emitter.on }, + $once: { get: () => $emitter.once }, + $options: { get: () => ({ componentName: instance.type.componentName }) }, + $parent: { + get: () => instance.parent && createVm({}, getRealParent(instance)) + }, + $refs: { get: () => instance.refs }, + $renderless: { get: () => instance.props.tiny_renderless }, + $scopedSlots: { get: () => instance.slots }, + $set: { get: () => $set }, + $slots: { get: () => instance.slots }, + $template: { get: () => instance.props.tiny_template } + }) + + return vm +} + +const onBeforeMount = (instance, refs) => { + for (let name in instance.refs) { + if (Object.prototype.hasOwnProperty.call(instance.refs, name)) { + refs[name] = instance.refs[name] + } + } +} + +export const tools = (context, mode) => { + const instance = hooks.getCurrentInstance() as any + const root = instance?.appContext.config.globalProperties + const { route, router } = useRouter(instance) + const i18n = instance?.proxy?.$root?.$i18n + const { dispatch, broadcast } = emitEvent(instance) + const parentHandler = parent(instance) + const childrenHandler = children(instance) + const vm = createVm({}, instance, context) + const emit = context.emit + const refs = {} + const grandParent = typeof instance.props.tiny_template === 'undefined' && getRealParent(instance) + const parentVm = grandParent ? createVm({}, grandParent) : instance.parent ? createVm({}, instance.parent) : null + + const setParentAttribute = ({ name, value }) => { + const ctx = grandParent ? grandParent.ctx : instance?.parent?.ctx + ctx[name] = value + + // 当前的parentVm也保存一下。 + parentVm[name] = value + } + + const defineInstanceProperties = (props) => { + Object.defineProperties(vm, props) + Object.defineProperties(instance?.ctx, props) + } + + const defineParentInstanceProperties = (props) => { + parentVm && Object.defineProperties(parentVm, props) + } + + hooks.onBeforeMount(() => defineInstanceVm(vm, instance)) + hooks.onMounted(() => onBeforeMount(instance, refs)) + + return { + framework: 'vue3', + vm, + emit, + emitter, + route, + router, + dispatch, + broadcast, + parentHandler, + childrenHandler, + i18n, + refs, + slots: instance?.slots, + scopedSlots: instance?.slots, + attrs: context.attrs, + parent: parentVm, + nextTick: hooks.nextTick, + constants: instance?.props._constants, + mode, + isPCMode: mode === 'pc', + isMobileMode: mode === 'mobile', + service: root?.$service, + getService: () => root?.$getService(vm), + setParentAttribute, + defineInstanceProperties, + defineParentInstanceProperties + } +} + +const mapping = (content, before, after) => { + if (typeof content[before] !== 'undefined') { + const fn = content[before] + + content[after] = (el, binding, vnode) => { + vnode.context = binding.instance + fn(el, binding, vnode) + } + + delete content[before] + } +} + +export const directive = (directives) => { + for (const name in directives) { + const content = directives[name] + + mapping(content, 'bind', 'beforeMount') + mapping(content, 'update', 'updated') + mapping(content, 'unbind', 'unmounted') + } + + return directives +} + +export const parseVnode = (vnode) => vnode + +const { Text, Comment } = hooks + +export const isEmptyVnode = (vnode) => !vnode || !vnode.type || [Text, Comment].includes(vnode.type) + +const parseProps = (propsData) => { + const props = {} + + for (const name in propsData) { + if (name === 'class' || name === 'style') { + props[name] = propsData[name] + } else if (name === 'on' || name === 'nativeOn') { + const events = propsData[name] + + for (const eventName in events) props[`on${capitalize(camelize(eventName))}`] = events[eventName] + } else if (name === 'attrs' || name === 'props' || name === 'domProps') { + const attrs = propsData[name] + + for (const key in attrs) props[key] = attrs[key] + } else { + props[name] = propsData[name] + } + } + + return props +} + +const customResolveComponent = (component) => { + let type = component + let customElement = false + + if (typeof component === 'string' && typeof document !== 'undefined') { + const el = document.createElement(component) + const svgTagNames = ['SVG', 'CIRCLE', 'PATH'] + + if ((el instanceof HTMLUnknownElement && !svgTagNames.includes(el.nodeName)) || component.includes('-')) { + component = component.toLowerCase() + customElement = true + + if (component === 'transition') type = hooks.Transition + else if (component === 'transition-group') type = hooks.TransitionGroup + else type = hooks.resolveComponent(component) + } else { + type = component + } + } + + return { type, component, customElement } +} + +type CreateElement = (component: any, propsData?: any, childData?: any) => ReturnType + +export const h: CreateElement = (component, propsData, childData) => { + let props = {} + let children = childData + const ret = customResolveComponent(component) + const customElement = ret.customElement + const type = ret.type + + component = ret.component + + if (propsData && typeof propsData === 'object' && !Array.isArray(propsData)) { + props = parseProps(propsData) + propsData.scopedSlots && (children = propsData.scopedSlots) + } else if (typeof propsData === 'string' || Array.isArray(propsData)) { + childData = propsData + } + + if (typeof childData === 'string' || Array.isArray(childData)) + children = typeof component !== 'string' || customElement ? () => childData : childData + + return hooks.h(type, props, children) +} + +export const createComponentFn = (design) => { + return ({ component, propsData, el }) => { + const comp = Object.assign(component, { provide: { [design.configKey]: design.configInstance } }) + const vnode = hooks.createVNode(comp, propsData) + + hooks.render(vnode, el) + return createVm({}, vnode.component) + } +} + +export const defineComponent = hooks.defineComponent + +export default hooks + +export const isVue2 = false + +export const isVue3 = true + +export const isVnode = hooks.isVNode + +export const KeepAlive = hooks.KeepAlive + +export type { + PropType, + ExtractPropTypes, + DefineComponent, + ComponentPublicInstance, + SetupContext, + ComputedRef +} from 'vue' diff --git a/packages/modules.json b/packages/modules.json index 27c6b7dd1..666b58b19 100644 --- a/packages/modules.json +++ b/packages/modules.json @@ -918,7 +918,8 @@ "type": "component", "exclude": false, "mode": [ - "pc" + "pc", + "mobile-first" ] }, "DividerPc": { @@ -926,6 +927,11 @@ "type": "template", "exclude": false }, + "DividerMobileFirst": { + "path": "vue/src/divider/src/mobile-first.vue", + "type": "template", + "exclude": false + }, "Drawer": { "path": "vue/src/drawer/index.ts", "type": "component", diff --git a/packages/renderless/package.json b/packages/renderless/package.json index 60a60bde0..419ada67a 100644 --- a/packages/renderless/package.json +++ b/packages/renderless/package.json @@ -43,4 +43,4 @@ "esno": "^4.7.0", "tsup": "7.2.0" } -} +} \ No newline at end of file diff --git a/packages/renderless/src/dialog-box/index.ts b/packages/renderless/src/dialog-box/index.ts index 7dc71a692..7a9bccbd4 100644 --- a/packages/renderless/src/dialog-box/index.ts +++ b/packages/renderless/src/dialog-box/index.ts @@ -56,6 +56,10 @@ export const computedStyle = } } + if (props.customStyle) { + style = Object.assign(style, props.customStyle) + } + return style } @@ -111,9 +115,9 @@ export const watchVisible = nextTick(() => state.key++) } - if (props.rightSlide) { - const dialogBoxDom = el.querySelector(constants.DIALOG_BOX_CLASS) || el - dialogBoxDom.style.left = '' + if (props.rightSlide && state.current !== 'default') { + const selector = `[data-tag=${constants.DIALOG_BOX_DATA_TAG}]` + props.rightSlide && (el.querySelector(selector).style.left = '') } } } diff --git a/packages/renderless/src/divider/index.ts b/packages/renderless/src/divider/index.ts new file mode 100644 index 000000000..c4afdf740 --- /dev/null +++ b/packages/renderless/src/divider/index.ts @@ -0,0 +1,57 @@ +import type { IDividerStyle, IDividerRenderlessParams } from '@/types' + +export const computedRootStyle = + ({ state, props }: Pick) => + (): IDividerStyle => { + return { + height: props.height || state.height, + margin: props.margin || state.margin, + fontSize: props.fontSize + } + } +export const computedLineStyle = + ({ props }: Pick) => + (): IDividerStyle => { + const lineStyle = { + borderTopStyle: props.borderStyle + } + + if (props.color) { + Object.assign(lineStyle, { borderTopColor: props.color }) + } + + return lineStyle + } + +export const computedTextStyle = + ({ props }: Pick) => + (): IDividerStyle => { + const textStyle = { + left: 'unset', + right: 'unset' + } + const defaultOffset = '5%' + + if (props.contentPosition === 'left') { + textStyle.left = props.offset || defaultOffset + } else if (props.contentPosition === 'right') { + textStyle.right = props.offset || defaultOffset + } + + return textStyle + } + +export const setDividerHeight = + ({ state, props, vm, nextTick }: Pick) => + (): void => { + const verticalHeight = '12px' + + if (props.direction === 'vertical') { + state.height = props.height || verticalHeight + } else { + nextTick(() => { + const offsetHeight = vm.$refs.text && vm.$refs.text.offsetHeight + state.height = props.height || offsetHeight ? offsetHeight + 'px' : 'auto' + }) + } + } diff --git a/packages/renderless/src/divider/vue.ts b/packages/renderless/src/divider/vue.ts index 26da32397..5bea16529 100644 --- a/packages/renderless/src/divider/vue.ts +++ b/packages/renderless/src/divider/vue.ts @@ -1,5 +1,42 @@ -export const api = [] +import type { + IDividerApi, + IDividerProps, + IDividerRenderlessParamUtils, + IDividerState, + ISharedRenderlessParamHooks +} from '@/types' +import { computedLineStyle, computedTextStyle, computedRootStyle, setDividerHeight } from './index' + +export const api = ['state'] + +export const renderless = ( + props: IDividerProps, + { reactive, onMounted, computed }: ISharedRenderlessParamHooks, + { vm, nextTick }: IDividerRenderlessParamUtils +) => { + const defaultMargin: string = '16px 0' + const verticalMargin: string = '0 8px' + + const api = {} as IDividerApi + const state: IDividerState = reactive({ + height: 'auto', + margin: props.direction === 'vertical' ? verticalMargin : defaultMargin, + lineStyle: computed(() => api.computedLineStyle()), + textStyle: computed(() => api.computedTextStyle()), + rootStyle: computed(() => api.computedRootStyle()) + }) + + Object.assign(api, { + state, + computedLineStyle: computedLineStyle({ props }), + computedTextStyle: computedTextStyle({ props }), + computedRootStyle: computedRootStyle({ props, state }), + setDividerHeight: setDividerHeight({ props, state, vm, nextTick }) + }) + + onMounted(() => { + api.setDividerHeight() + }) -export const renderless = () => { return api } diff --git a/packages/renderless/src/dropdown/index.ts b/packages/renderless/src/dropdown/index.ts index fb8fc6223..3dfa5aa35 100644 --- a/packages/renderless/src/dropdown/index.ts +++ b/packages/renderless/src/dropdown/index.ts @@ -177,7 +177,7 @@ export const initAria = } } -const toggleFocus = +export const toggleFocus = ({ state, value }) => () => { state.focusing = value @@ -194,9 +194,9 @@ export const initEvent = state.dropdownElm?.addEventListener('keydown', api.handleItemKeyDown, true) if (!props.splitButton || !props.singleButton) { - on(state.triggerElm, 'focus', toggleFocus({ state, value: true })) - on(state.triggerElm, 'blur', toggleFocus({ state, value: false })) - on(state.triggerElm, 'click', toggleFocus({ state, value: false })) + on(state.triggerElm, 'focus', api.toggleFocusOnTrue) + on(state.triggerElm, 'blur', api.toggleFocusOnFalse) + on(state.triggerElm, 'click', api.toggleFocusOnFalse) } if (state.trigger === 'hover') { @@ -270,9 +270,9 @@ export const beforeDistory = () => { if (state.triggerElm) { off(state.triggerElm, 'keydown', api.handleTriggerKeyDown) - off(state.triggerElm, 'focus', toggleFocus({ state, value: true })) - off(state.triggerElm, 'blur', toggleFocus({ state, value: false })) - off(state.triggerElm, 'click', toggleFocus({ state, value: false })) + off(state.triggerElm, 'focus', api.toggleFocusOnTrue) + off(state.triggerElm, 'blur', api.toggleFocusOnFalse) + off(state.triggerElm, 'click', api.toggleFocusOnFalse) off(state.triggerElm, 'mouseenter', api.show) off(state.triggerElm, 'mouseleave', api.hide) off(state.triggerElm, 'click', api.handleClick) diff --git a/packages/renderless/src/dropdown/vue.ts b/packages/renderless/src/dropdown/vue.ts index d089acf18..009819d74 100644 --- a/packages/renderless/src/dropdown/vue.ts +++ b/packages/renderless/src/dropdown/vue.ts @@ -36,14 +36,15 @@ import { initDomOperation, mounted, beforeDistory, - clickOutside + clickOutside, + toggleFocus } from './index' export const api = ['state', 'handleMainButtonClick', 'hide', 'show', 'initDomOperation', 'handleClick', 'clickOutside'] export const renderless = ( props: IDropdownProps, - { reactive, watch, provide, onMounted, computed }: ISharedRenderlessParamHooks, + { reactive, watch, provide, onMounted, computed, onBeforeUnmount }: ISharedRenderlessParamHooks, { emit, parent, broadcast, vm, nextTick, mode, designConfig }: IDropdownRenderlessParamUtils ): IDropdownApi => { const api = {} as IDropdownApi @@ -85,13 +86,16 @@ export const renderless = ( triggerElmFocus: triggerElmFocus(state), initDomOperation: initDomOperation({ api, state, vm }), beforeDistory: beforeDistory({ vm, api, state }), - clickOutside: clickOutside({ props, api }) + clickOutside: clickOutside({ props, api }), + toggleFocusOnTrue: toggleFocus({ state, value: true }), + toggleFocusOnFalse: toggleFocus({ state, value: false }) }) watch(() => state.visible, api.watchVisible) watch(() => state.focusing, api.watchFocusing) onMounted(api.mounted) + onBeforeUnmount(api.beforeDistory) return api } diff --git a/packages/renderless/src/file-upload/index.ts b/packages/renderless/src/file-upload/index.ts index 587e00d54..611c43422 100644 --- a/packages/renderless/src/file-upload/index.ts +++ b/packages/renderless/src/file-upload/index.ts @@ -1511,7 +1511,7 @@ export const downloadFileSingleInner = export const getDownloadFileInfo = ({ api, state, props, service }: Pick) => - ({ docId }: { docId: string }) => { + ({ docId, docVersion }: { docId: string; docVersion: string }) => { return service.getDocumentInfoUrl().then((url) => { return new Promise((resolve, reject) => { service diff --git a/packages/renderless/src/form/vue.ts b/packages/renderless/src/form/vue.ts index 1ed8ff56c..96d465e0e 100644 --- a/packages/renderless/src/form/vue.ts +++ b/packages/renderless/src/form/vue.ts @@ -116,7 +116,7 @@ export const renderless = ( onBeforeUnmount(unbindDialogEvent) - watch(() => props.rules, api.watchRules) + watch(() => props.rules, api.watchRules, { deep: props.validateOnRuleChange === 'deep' }) return api } diff --git a/packages/renderless/src/rich-text-editor/vue.ts b/packages/renderless/src/rich-text-editor/vue.ts index dab654463..1f1674809 100644 --- a/packages/renderless/src/rich-text-editor/vue.ts +++ b/packages/renderless/src/rich-text-editor/vue.ts @@ -1,14 +1,14 @@ import { + Active, + closeTablePanel, + eventClick, + eventImg, handleChange, setLink, - tableMouseMove, - tableChoose, - toggleTablePanel, - closeTablePanel, shouldShow, - eventImg, - eventClick, - Active + tableChoose, + tableMouseMove, + toggleTablePanel } from './index' import type { ISharedRenderlessParamHooks } from '@/types' @@ -261,11 +261,11 @@ export const renderless = ( onDestroy() { // The editor is being destroyed. emit('destroy') - }, - ...props.options + } } - let options = Object.assign(defaultOptions, props.options) + let options = { ...defaultOptions, ...props.options } + options.extensions = [...new Set([...defaultOptions.extensions, ...(props.options.extensions || [])])] const state = reactive({ editor: new Editor(options), diff --git a/packages/renderless/src/select/index.ts b/packages/renderless/src/select/index.ts index 71ebcca92..33d779c80 100644 --- a/packages/renderless/src/select/index.ts +++ b/packages/renderless/src/select/index.ts @@ -572,6 +572,11 @@ export const handleFocus = if (!state.willFocusRun) return // 立即触发了blur,则不执行focus了 if (!state.softFocus) { + // tiny 新增 shape条件: 防止过滤器模式,且filterable时, 面板无法关闭的bug + if (props.shape === 'filter') { + return + } + if (props.automaticDropdown || props.filterable || props.searchable) { state.visible = true state.softFocus = true diff --git a/packages/renderless/src/tree-menu/index.ts b/packages/renderless/src/tree-menu/index.ts index 0d267cddb..917f1ae7a 100644 --- a/packages/renderless/src/tree-menu/index.ts +++ b/packages/renderless/src/tree-menu/index.ts @@ -27,6 +27,12 @@ export const initData = } } +export const getTree = + ({ vm }) => + () => { + return vm.$refs.tree + } + export const setMenuKey = (api: ITreeMenuApi) => ({ newData, menuData }: { newData: ITreeMenuNewData[]; menuData: ITreeMenuData[] }) => { diff --git a/packages/renderless/src/tree-menu/vue.ts b/packages/renderless/src/tree-menu/vue.ts index eec8857dd..bdd89a6c6 100644 --- a/packages/renderless/src/tree-menu/vue.ts +++ b/packages/renderless/src/tree-menu/vue.ts @@ -35,7 +35,8 @@ import { setCurrentNode, getCurrentNode, handleToggleMenu, - computedTreeStyle + computedTreeStyle, + getTree } from './index' import type { ISharedRenderlessParamUtils, @@ -70,7 +71,8 @@ export const api = [ 'getCurrentKey', 'setCurrentNode', 'getCurrentNode', - 'handleToggleMenu' + 'handleToggleMenu', + 'getTree' ] export const renderless = ( @@ -121,6 +123,7 @@ export const renderless = ( getCurrentKey: getCurrentKey({ vm }), setCurrentNode: setCurrentNode({ vm }), getCurrentNode: getCurrentNode({ vm }), + getTree: getTree({ vm }), handleToggleMenu: handleToggleMenu({ state, vm }), computedTreeStyle: computedTreeStyle({ props }) }) diff --git a/packages/renderless/src/year-table/index.ts b/packages/renderless/src/year-table/index.ts index 9573390f5..7931cc797 100644 --- a/packages/renderless/src/year-table/index.ts +++ b/packages/renderless/src/year-table/index.ts @@ -28,7 +28,7 @@ export const getIsDisabled = ({ props }) => (year) => { return props.selectionMode.startsWith('year') && typeof props.disabledDate === 'function' - ? props.disabledDate(year) + ? props.disabledDate(new Date(year, 0, 1, 0)) : false } @@ -87,7 +87,7 @@ export const getRows = cell.text = year cell.type = isToday ? DATEPICKER.Today : DATEPICKER.Normal if (props.selectionMode.startsWith('year')) { - cell.disabled = typeof disabledDate === 'function' && disabledDate(year) + cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(year, 0, 1, 0)) } if (selectionMode === DATEPICKER.YearRange) { diff --git a/packages/renderless/types/divider.type.ts b/packages/renderless/types/divider.type.ts new file mode 100644 index 000000000..c7b62f3bc --- /dev/null +++ b/packages/renderless/types/divider.type.ts @@ -0,0 +1,41 @@ +import type { ExtractPropTypes } from 'vue' +import type { dividerProps } from '@/divider/src' +import type { computedLineStyle, computedTextStyle, computedRootStyle, setDividerHeight } from '../src/divider' +import type { ISharedRenderlessFunctionParams, ISharedRenderlessParamUtils } from './shared.type' + +export interface IDividerState { + height: string + margin: string + lineStyle: IDividerStyle + textStyle: IDividerStyle + rootStyle: IDividerStyle +} + +export type IDividerProps = ExtractPropTypes + +export interface IDividerApi { + state: IDividerState + computedLineStyle: ReturnType + computedTextStyle: ReturnType + computedRootStyle: ReturnType + setDividerHeight: ReturnType +} + +export type IDividerRenderlessParams = ISharedRenderlessFunctionParams & { + api: IDividerApi + state: IDividerState + props: IDividerProps +} + +export type IDividerRenderlessParamUtils = ISharedRenderlessParamUtils + +export interface IDividerStyle { + margin?: string | number + height?: string | number + fontSize?: string | number + right?: string | number + left?: string | number + borderLeftStyle?: string | number + borderTopStyle?: string | number + borderTopColor?: string | number +} diff --git a/packages/renderless/types/dropdown.type.ts b/packages/renderless/types/dropdown.type.ts index 8096e6fbe..2397fc0ee 100644 --- a/packages/renderless/types/dropdown.type.ts +++ b/packages/renderless/types/dropdown.type.ts @@ -50,6 +50,8 @@ export interface IDropdownApi { initDomOperation: () => void beforeDistory: () => void clickOutside: () => void + toggleFocusOnTrue: () => void + toggleFocusOnFalse: () => void } export type IDropdownRenderlessParams = ISharedRenderlessFunctionParams & { diff --git a/packages/renderless/types/index.ts b/packages/renderless/types/index.ts index aad985693..71098950b 100644 --- a/packages/renderless/types/index.ts +++ b/packages/renderless/types/index.ts @@ -82,6 +82,7 @@ export * from './dropdown-item.type' export * from './dropdown-menu.type' export * from './dynamic-scroller.type' export * from './dynamic-scroller-item.type' +export * from './divider.type' export * from './espace.type' export * from './exception.type' export * from './fall-menu.type' diff --git a/packages/renderless/types/tree-menu.type.ts b/packages/renderless/types/tree-menu.type.ts index 006098f6e..1f8c96358 100644 --- a/packages/renderless/types/tree-menu.type.ts +++ b/packages/renderless/types/tree-menu.type.ts @@ -23,7 +23,10 @@ import type { setCurrentKey, getCurrentKey, setCurrentNode, - getCurrentNode + getCurrentNode, + handleToggleMenu, + computedTreeStyle, + getTree } from '../src/tree-menu' import type { ISharedRenderlessParamUtils } from './shared.type' @@ -51,6 +54,7 @@ export interface ITreeMenuApi { currentChange: ReturnType watchFilterText: ReturnType getTitle: ReturnType + getTree: ReturnType setMenuKey: ReturnType initData: ReturnType collapseChange: ReturnType @@ -60,6 +64,8 @@ export interface ITreeMenuApi { getCurrentKey: ReturnType setCurrentNode: ReturnType getCurrentNode: ReturnType + handleToggleMenu: ReturnType + computedTreeStyle: ReturnType } export interface ITreeMenuData { diff --git a/packages/theme-mobile/src/modal/index.less b/packages/theme-mobile/src/modal/index.less index 422bd7e99..d9bbad886 100644 --- a/packages/theme-mobile/src/modal/index.less +++ b/packages/theme-mobile/src/modal/index.less @@ -152,6 +152,7 @@ .@{modal-prefix-cls}__body { white-space: normal; word-break: break-word; + overflow: auto; } } diff --git a/packages/theme-saas/src/divider/index.less b/packages/theme-saas/src/divider/index.less index e69de29bb..a13b25bab 100644 --- a/packages/theme-saas/src/divider/index.less +++ b/packages/theme-saas/src/divider/index.less @@ -0,0 +1,71 @@ +@import '../custom.less'; + +@divider-prefix-cls: ~'@{css-prefix}divider'; + +.@{divider-prefix-cls} { + @apply h-auto; + @apply flex; + @apply items-center; + @apply justify-center; + @apply relative; + @apply w-full; + @apply overflow-hidden; + + & &--default, + &&--default { + @apply border-color-border; + } + + & &--info, + &&--info { + @apply border-color-brand; + } + + & &--error, + &&--error { + @apply border-color-error; + } + + & &--warning, + &&--warning { + @apply border-color-warning; + } + + & &--success, + &&--success { + @apply border-color-success; + } + + &--horizontal { + @apply mt-24 mr-0 mb-24 ml-0; + } + + &--vertical { + @apply inline-block; + @apply w-1; + @apply align-middle; + @apply mt-0 mr-8 mb-0 ml-8; + height: 1em; + @apply border-l border-l-color-border; + } + + &__text { + @apply absolute; + @apply font-medium; + @apply pt-0 pr-14 pb-0 pl-14; + @apply text-color-text-primary; + @apply bg-color-bg-1; + } + + .@{divider-prefix-cls}-line { + @apply h-px; + @apply w-full; + @apply border-t; + } + + .@{divider-prefix-cls}-text { + @apply absolute; + @apply pt-0 pr-14 pb-0 pl-14; + @apply bg-white; + } +} diff --git a/packages/theme-saas/src/modal/index.less b/packages/theme-saas/src/modal/index.less index dc4041a35..78f4a7247 100644 --- a/packages/theme-saas/src/modal/index.less +++ b/packages/theme-saas/src/modal/index.less @@ -5,6 +5,8 @@ @custom-prefix-cls: ~'@{css-prefix}custom'; .@{modal-prefix-cls} { + overflow-wrap: break-word; + &__wrapper { @apply hidden; @apply fixed; @@ -141,8 +143,7 @@ &.type__confirm { .@{modal-prefix-cls}__body { @apply whitespace-normal; - word-wrap: break-word; - @apply break-all; + word-break: break-word; @apply overflow-auto; } } diff --git a/packages/theme-saas/src/rich-text/index.less b/packages/theme-saas/src/rich-text/index.less index 282811650..dcc52d1d9 100644 --- a/packages/theme-saas/src/rich-text/index.less +++ b/packages/theme-saas/src/rich-text/index.less @@ -97,6 +97,7 @@ @apply whitespace-pre-wrap; white-space-collapse: preserve-breaks; word-wrap: break-word; + word-break: break-word; & > * { @apply cursor-text; diff --git a/packages/theme-saas/src/select-dropdown/index.less b/packages/theme-saas/src/select-dropdown/index.less index 43dae7f15..0d52ca0a9 100644 --- a/packages/theme-saas/src/select-dropdown/index.less +++ b/packages/theme-saas/src/select-dropdown/index.less @@ -91,6 +91,12 @@ > span > .tiny-svg { @apply ~'-mt-0.5'; } + &:first-child { + > .tiny-svg, + > span > .tiny-svg { + margin-top: 1px + } + } } & &__loading { diff --git a/packages/theme/src/divider/index.less b/packages/theme/src/divider/index.less index b914032ca..904f7d7eb 100644 --- a/packages/theme/src/divider/index.less +++ b/packages/theme/src/divider/index.less @@ -6,14 +6,43 @@ .@{divider-prefix-cls} { .inject-Divider-vars(); position: relative; + height: auto; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + overflow: hidden; - &&--horizontal { - display: block; - margin: 24px 0; - border-top: 1px solid var(--tv-Divider-dividing-line); + & &--default, + &&--default { + border-color: var(--tv-Divider-default-color); } - &&--vertical { + & &--success, + &&--success { + border-color: var(--tv-Divider-success-color); + } + + & &--warning, + &&--warning { + border-color: var(--tv-Divider-warning-color); + } + + & &--info, + &&--info { + border-color: var(--tv-Divider-info-color); + } + + & &--error, + &&--error { + border-color: var(--tv-Divider-error-color); + } + + &--horizontal { + margin: 24px 0; + } + + &--vertical { display: inline-block; width: 1px; height: 1em; @@ -24,24 +53,22 @@ &__text { position: absolute; - font-size: 14px; font-weight: 500; + padding: 0 14px; color: var(--tv-Divider-text-color); background-color: var(--tv-Divider-text-bg-color); + line-height: normal; + } - &.is-left { - left: 20px; - transform: translateY(-50%); - } + .@{divider-prefix-cls}-line { + height: 1px; + width: 100%; + border-top-width: var(--tv-Divider-border-width); + } - &.is-center { - left: 50%; - transform: translate(-50%) translateY(-50%); - } - - &.is-right { - right: 20px; - transform: translateY(-50%); - } + .@{divider-prefix-cls}-text { + position: absolute; + padding: 0 14px; + background-color: var(--tv-Divider-text-bg-color); } } diff --git a/packages/theme/src/divider/vars.less b/packages/theme/src/divider/vars.less index ee5839db4..bc958b4ba 100644 --- a/packages/theme/src/divider/vars.less +++ b/packages/theme/src/divider/vars.less @@ -5,4 +5,16 @@ --tv-Divider-text-bg-color: var(--tv-color-border-divider); // 文案文本色 --tv-Divider-text-color: var(--tv-color-text); + // 成功颜色 + --tv-Divider-success-color: var(--tv-color-success-border); + // 默认颜色 + --tv-Divider-default-color: var(--tv-color-border-divider-short); + // 告警颜色 + --tv-Divider-warning-color: var(--tv-color-warn-border); + // 信息颜色 + --tv-Divider-info-color: var(--tv-color-info-border); + // 错误颜色 + --tv-Divider-error-color: var(--tv-color-error-border); + // 宽度 + --tv-Divider-border-width: var(--tv-border-width); } diff --git a/packages/utils/src/crypt/core.ts b/packages/utils/src/crypt/core.ts index f26886340..414f9edb0 100644 --- a/packages/utils/src/crypt/core.ts +++ b/packages/utils/src/crypt/core.ts @@ -333,7 +333,6 @@ export class Hasher extends BufferedBlockAlgorithm { if (messageUpdate) { this._append(messageUpdate) } - // @ts-ignore const hash = this._doFinalize() diff --git a/packages/vue-directive/src/highlight-query.ts b/packages/vue-directive/src/highlight-query.ts index 23a9d58fd..615bc81ba 100644 --- a/packages/vue-directive/src/highlight-query.ts +++ b/packages/vue-directive/src/highlight-query.ts @@ -15,7 +15,7 @@ function editNodes(el: HTMLElement, nodes: HTMLElement[], query: string) { // 2、处理收集后的节点,字符串搜索性能优于正则替换 nodes.forEach((node) => { const content = node.textContent as string - const start = content.toLowerCase().indexOf(query.toLowerCase()) + const start = content.indexOf(query) const startText = content.substring(0, start) const endText = content.substring(start + query.length) @@ -58,7 +58,7 @@ function edit(el: HTMLElement, query: string) { } const content = node.textContent || '' - return content.toLowerCase().includes(query.toLowerCase()) + return content.includes(query) }) editNodes(el, matchNodes, query) diff --git a/packages/vue-locale/src/lang/en.ts b/packages/vue-locale/src/lang/en.ts index df39dcd05..ed2b189b7 100644 --- a/packages/vue-locale/src/lang/en.ts +++ b/packages/vue-locale/src/lang/en.ts @@ -194,7 +194,7 @@ export default { hour: 'hour', minute: 'minute', second: 'second', - to: '', + to: '-', yearMonth: '{month} {year}', yearMonthDay: '{month} {day}, {year}' }, diff --git a/packages/vue/src/dialog-box/src/index.ts b/packages/vue/src/dialog-box/src/index.ts index 213a30295..aabd3f8ad 100644 --- a/packages/vue/src/dialog-box/src/index.ts +++ b/packages/vue/src/dialog-box/src/index.ts @@ -21,6 +21,7 @@ export const $constants = { DIALOG_BOX_CLASS: 'div.tiny-dialog-box', PC_SCROLL_LOCK_CLASS: 'dialog-box__scroll-lock', MOBILE_SCROLL_LOCK_CLASS: 'mobile-dialog-box__scroll-lock', + DIALOG_BOX_DATA_TAG: 'tiny-dialog-box', Mode: 'pc', SCROLL_LOCK_CLASS(mode) { return mode === this.Mode ? this.PC_SCROLL_LOCK_CLASS : this.MOBILE_SCROLL_LOCK_CLASS @@ -122,6 +123,14 @@ export const dialogBoxProps = { dialogTransition: { type: String, default: '' + }, + noAnimation: { + type: Boolean, + default: false + }, + customStyle: { + type: Object, + default: () => ({}) } } diff --git a/packages/vue/src/dialog-box/src/mobile-first.vue b/packages/vue/src/dialog-box/src/mobile-first.vue index c6e9e4db3..f3c6d83d9 100644 --- a/packages/vue/src/dialog-box/src/mobile-first.vue +++ b/packages/vue/src/dialog-box/src/mobile-first.vue @@ -1,7 +1,12 @@