forked from opentiny/tiny-vue
fix(select): fix select/picker bugs (#1487)
This commit is contained in:
parent
a70d32573b
commit
85ce304b76
|
@ -393,6 +393,18 @@ export default {
|
||||||
mode: ['mobile-first'],
|
mode: ['mobile-first'],
|
||||||
mfDemo: ''
|
mfDemo: ''
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'string-mode',
|
||||||
|
type: 'Boolean',
|
||||||
|
defaultValue: '',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '使用字符串模式,精度超过JS限制时使用',
|
||||||
|
'en-US': ''
|
||||||
|
},
|
||||||
|
mode: ['pc', 'mobile', 'mobile-first'],
|
||||||
|
pcDemo: 'string-mode',
|
||||||
|
mfDemo: ''
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'value',
|
name: 'value',
|
||||||
type: 'Number',
|
type: 'Number',
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="gray-bg">
|
<div class="gray-bg">
|
||||||
<tiny-button ghost>幽灵按钮</tiny-button>
|
<tiny-button ghost reset-time="0">幽灵按钮</tiny-button>
|
||||||
<tiny-button ghost type="primary">主要按钮</tiny-button>
|
<tiny-button ghost type="primary" reset-time="0">主要按钮</tiny-button>
|
||||||
<tiny-button ghost type="success">成功按钮</tiny-button>
|
<tiny-button ghost type="success" reset-time="0">成功按钮</tiny-button>
|
||||||
<tiny-button ghost type="info">信息按钮</tiny-button>
|
<tiny-button ghost type="info" reset-time="0">信息按钮</tiny-button>
|
||||||
<tiny-button ghost type="warning">告警按钮</tiny-button>
|
<tiny-button ghost type="warning" reset-time="0">告警按钮</tiny-button>
|
||||||
<tiny-button ghost type="danger">危险按钮</tiny-button>
|
<tiny-button ghost type="danger" reset-time="0">危险按钮</tiny-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
const getGhostBtn = (index: number) => demo.locator('.tiny-button').nth(index)
|
const getGhostBtn = (index: number) => demo.locator('.tiny-button').nth(index)
|
||||||
|
|
||||||
// 默认幽灵按钮
|
// 默认幽灵按钮
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
await expect(getGhostBtn(0)).toHaveCSS('color', 'rgb(37, 43, 58)')
|
await expect(getGhostBtn(0)).toHaveCSS('color', 'rgb(37, 43, 58)')
|
||||||
await expect(getGhostBtn(0)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(0)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(0)).toHaveCSS('border-bottom-color', 'rgb(173, 176, 184)')
|
await expect(getGhostBtn(0)).toHaveCSS('border-bottom-color', 'rgb(173, 176, 184)')
|
||||||
await getGhostBtn(0).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(0).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(0)).toHaveCSS('color', 'rgb(94, 124, 224)')
|
await expect(getGhostBtn(0)).toHaveCSS('color', 'rgb(94, 124, 224)')
|
||||||
await expect(getGhostBtn(0)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(0)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
@ -21,7 +23,8 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
await expect(getGhostBtn(1)).toHaveCSS('color', 'rgb(94, 124, 224)')
|
await expect(getGhostBtn(1)).toHaveCSS('color', 'rgb(94, 124, 224)')
|
||||||
await expect(getGhostBtn(1)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(1)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(1)).toHaveCSS('border-bottom-color', 'rgb(94, 124, 224)')
|
await expect(getGhostBtn(1)).toHaveCSS('border-bottom-color', 'rgb(94, 124, 224)')
|
||||||
await getGhostBtn(1).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(1).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(1)).toHaveCSS('color', 'rgb(118, 147, 245)')
|
await expect(getGhostBtn(1)).toHaveCSS('color', 'rgb(118, 147, 245)')
|
||||||
await expect(getGhostBtn(1)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(1)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
@ -31,7 +34,8 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
await expect(getGhostBtn(2)).toHaveCSS('color', 'rgb(80, 212, 171)')
|
await expect(getGhostBtn(2)).toHaveCSS('color', 'rgb(80, 212, 171)')
|
||||||
await expect(getGhostBtn(2)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(2)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(2)).toHaveCSS('border-bottom-color', 'rgb(80, 212, 171)')
|
await expect(getGhostBtn(2)).toHaveCSS('border-bottom-color', 'rgb(80, 212, 171)')
|
||||||
await getGhostBtn(2).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(2).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(2)).toHaveCSS('color', 'rgb(172, 242, 220)')
|
await expect(getGhostBtn(2)).toHaveCSS('color', 'rgb(172, 242, 220)')
|
||||||
await expect(getGhostBtn(2)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(2)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
@ -41,7 +45,8 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
await expect(getGhostBtn(3)).toHaveCSS('color', 'rgb(37, 43, 58)')
|
await expect(getGhostBtn(3)).toHaveCSS('color', 'rgb(37, 43, 58)')
|
||||||
await expect(getGhostBtn(3)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(3)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(3)).toHaveCSS('border-bottom-color', 'rgb(37, 43, 58)')
|
await expect(getGhostBtn(3)).toHaveCSS('border-bottom-color', 'rgb(37, 43, 58)')
|
||||||
await getGhostBtn(3).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(3).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(3)).toHaveCSS('color', 'rgb(92, 97, 115)')
|
await expect(getGhostBtn(3)).toHaveCSS('color', 'rgb(92, 97, 115)')
|
||||||
await expect(getGhostBtn(3)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(3)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
@ -51,7 +56,8 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
await expect(getGhostBtn(4)).toHaveCSS('color', 'rgb(250, 152, 65)')
|
await expect(getGhostBtn(4)).toHaveCSS('color', 'rgb(250, 152, 65)')
|
||||||
await expect(getGhostBtn(4)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(4)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(4)).toHaveCSS('border-bottom-color', 'rgb(250, 152, 65)')
|
await expect(getGhostBtn(4)).toHaveCSS('border-bottom-color', 'rgb(250, 152, 65)')
|
||||||
await getGhostBtn(4).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(4).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(4)).toHaveCSS('color', 'rgb(250, 194, 10)')
|
await expect(getGhostBtn(4)).toHaveCSS('color', 'rgb(250, 194, 10)')
|
||||||
await expect(getGhostBtn(4)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(4)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
@ -61,7 +67,8 @@ test('幽灵按钮', async ({ page }) => {
|
||||||
await expect(getGhostBtn(5)).toHaveCSS('color', 'rgb(199, 0, 11)')
|
await expect(getGhostBtn(5)).toHaveCSS('color', 'rgb(199, 0, 11)')
|
||||||
await expect(getGhostBtn(5)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(5)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
await expect(getGhostBtn(5)).toHaveCSS('border-bottom-color', 'rgb(199, 0, 11)')
|
await expect(getGhostBtn(5)).toHaveCSS('border-bottom-color', 'rgb(199, 0, 11)')
|
||||||
await getGhostBtn(5).hover()
|
await page.waitForTimeout(100)
|
||||||
|
await getGhostBtn(5).click()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(getGhostBtn(5)).toHaveCSS('color', 'rgb(214, 74, 82)')
|
await expect(getGhostBtn(5)).toHaveCSS('color', 'rgb(214, 74, 82)')
|
||||||
await expect(getGhostBtn(5)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
await expect(getGhostBtn(5)).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)')
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="gray-bg">
|
<div class="gray-bg">
|
||||||
<tiny-button ghost>幽灵按钮</tiny-button>
|
<tiny-button ghost reset-time="0">幽灵按钮</tiny-button>
|
||||||
<tiny-button ghost type="primary">主要按钮</tiny-button>
|
<tiny-button ghost reset-time="0" type="primary">主要按钮</tiny-button>
|
||||||
<tiny-button ghost type="success">成功按钮</tiny-button>
|
<tiny-button ghost reset-time="0" type="success">成功按钮</tiny-button>
|
||||||
<tiny-button ghost type="info">信息按钮</tiny-button>
|
<tiny-button ghost reset-time="0" type="info">信息按钮</tiny-button>
|
||||||
<tiny-button ghost type="warning">告警按钮</tiny-button>
|
<tiny-button ghost reset-time="0" type="warning">告警按钮</tiny-button>
|
||||||
<tiny-button ghost type="danger">危险按钮</tiny-button>
|
<tiny-button ghost reset-time="0" type="danger">危险按钮</tiny-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ test('鼠标滚轮事件', async ({ page }) => {
|
||||||
const numeric = page.getByRole('spinbutton')
|
const numeric = page.getByRole('spinbutton')
|
||||||
const initVal = Number(await numeric.inputValue())
|
const initVal = Number(await numeric.inputValue())
|
||||||
await numeric.click()
|
await numeric.click()
|
||||||
await page.mouse.wheel(0, -100)
|
await page.mouse.wheel(0, -500)
|
||||||
const currentVal = Number(await numeric.inputValue())
|
const currentVal = Number(await numeric.inputValue())
|
||||||
expect(currentVal).toBeGreaterThanOrEqual(initVal)
|
expect(currentVal).toBeLessThan(initVal)
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<template>
|
||||||
|
<tiny-numeric style="width: 500px" v-model="stepNum" :step="step" string-mode :precision="20"></tiny-numeric>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Numeric as TinyNumeric } from '@opentiny/vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
const step = ref('0.00000000000000000002')
|
||||||
|
const stepNum = ref('0.00000000000000000002')
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('高精度', async ({ page }) => {
|
||||||
|
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||||
|
await page.goto('numeric#string-mode')
|
||||||
|
|
||||||
|
const input = page.getByRole('spinbutton')
|
||||||
|
const increaseBtn = page.locator('.tiny-numeric__increase')
|
||||||
|
const decreaseBtn = page.locator('.tiny-numeric__decrease')
|
||||||
|
await increaseBtn.click()
|
||||||
|
const increasedVal = await input.inputValue()
|
||||||
|
expect(increasedVal).toContain('0.00000000000000000004')
|
||||||
|
|
||||||
|
await decreaseBtn.click()
|
||||||
|
const decreasedVal = await input.inputValue()
|
||||||
|
expect(decreasedVal).toContain('0.00000000000000000002')
|
||||||
|
})
|
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<tiny-numeric style="width: 500px" v-model="stepNum" :step="step" string-mode :precision="20"></tiny-numeric>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Numeric } from '@opentiny/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TinyNumeric: Numeric
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
step: '0.00000000000000000002',
|
||||||
|
stepNum: '0.00000000000000000002'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -171,6 +171,19 @@ export default {
|
||||||
},
|
},
|
||||||
codeFiles: ['blur-event.vue']
|
codeFiles: ['blur-event.vue']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
demoId: 'string-mode',
|
||||||
|
name: {
|
||||||
|
'zh-CN': '高精度',
|
||||||
|
'en-US': 'Out of Focus Event'
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
'zh-CN':
|
||||||
|
'<p>可通过 <code>string-mode</code> 设置高精度模式,当 JS 默认的 Number 不满足数字的长度与精度需求时。</p>\n',
|
||||||
|
'en-US': '<p>The<code>@blur</code>event is triggered when the text box loses focus. </p>\n'
|
||||||
|
},
|
||||||
|
codeFiles: ['string-mode.vue']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
demoId: 'filter-mode',
|
demoId: 'filter-mode',
|
||||||
name: {
|
name: {
|
||||||
|
|
|
@ -82,12 +82,12 @@ const options2 = ref([
|
||||||
{ value: '选项1', label: '黄金糕' },
|
{ value: '选项1', label: '黄金糕' },
|
||||||
{ value: '选项2', label: '双皮奶', disabled: true },
|
{ value: '选项2', label: '双皮奶', disabled: true },
|
||||||
{ value: '选项3', label: '蚵仔煎' },
|
{ value: '选项3', label: '蚵仔煎' },
|
||||||
{ value: '选项4', label: '龙须面' },
|
{ value: '选项4', label: '龙须面', disabled: true },
|
||||||
{ value: '选项5', label: '北京烤鸭' }
|
{ value: '选项5', label: '北京烤鸭' }
|
||||||
])
|
])
|
||||||
|
|
||||||
const value1 = ref('')
|
const value1 = ref('')
|
||||||
const value2 = ref([])
|
const value2 = ref(['选项2'])
|
||||||
const value3 = ref('')
|
const value3 = ref('')
|
||||||
const value4 = ref(['选项2', '选项3'])
|
const value4 = ref(['选项2', '选项3'])
|
||||||
const value5 = ref(['选项1', '选项2', '选项3', '选项4', '选项5'])
|
const value5 = ref(['选项1', '选项2', '选项3', '选项4', '选项5'])
|
||||||
|
|
|
@ -19,15 +19,15 @@ test('多选某项禁用', async ({ page }) => {
|
||||||
const tag = select.locator('.tiny-tag')
|
const tag = select.locator('.tiny-tag')
|
||||||
const option = dropdown.locator('.tiny-option')
|
const option = dropdown.locator('.tiny-option')
|
||||||
|
|
||||||
await expect(tag).toHaveCount(0)
|
await expect(tag).toHaveCount(1)
|
||||||
await select.click()
|
await select.click()
|
||||||
await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/is-disabled/)
|
await expect(option.filter({ hasText: '双皮奶' })).toHaveClass(/is-disabled/)
|
||||||
|
|
||||||
await option.filter({ hasText: '双皮奶' }).click()
|
await option.filter({ hasText: '双皮奶' }).click()
|
||||||
await expect(tag).toHaveCount(0)
|
await expect(tag).toHaveCount(1)
|
||||||
|
|
||||||
await option.filter({ hasText: '黄金糕' }).click()
|
await option.filter({ hasText: '黄金糕' }).click()
|
||||||
await expect(tag).toHaveCount(1)
|
await expect(tag).toHaveCount(2)
|
||||||
await expect(tag.filter({ hasText: '黄金糕' })).toHaveCount(1)
|
await expect(tag.filter({ hasText: '黄金糕' })).toHaveCount(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -87,11 +87,11 @@ export default {
|
||||||
{ value: '选项1', label: '黄金糕' },
|
{ value: '选项1', label: '黄金糕' },
|
||||||
{ value: '选项2', label: '双皮奶', disabled: true },
|
{ value: '选项2', label: '双皮奶', disabled: true },
|
||||||
{ value: '选项3', label: '蚵仔煎' },
|
{ value: '选项3', label: '蚵仔煎' },
|
||||||
{ value: '选项4', label: '龙须面' },
|
{ value: '选项4', label: '龙须面', disabled: true },
|
||||||
{ value: '选项5', label: '北京烤鸭' }
|
{ value: '选项5', label: '北京烤鸭' }
|
||||||
],
|
],
|
||||||
value1: '',
|
value1: '',
|
||||||
value2: [],
|
value2: ['选项2'],
|
||||||
value3: '',
|
value3: '',
|
||||||
value4: ['选项2', '选项3'],
|
value4: ['选项2', '选项3'],
|
||||||
value5: ['选项1', '选项2', '选项3', '选项4', '选项5']
|
value5: ['选项1', '选项2', '选项3', '选项4', '选项5']
|
||||||
|
|
|
@ -26,7 +26,7 @@ test('单选事件', async ({ page }) => {
|
||||||
|
|
||||||
await page.waitForTimeout(200)
|
await page.waitForTimeout(200)
|
||||||
await input.hover()
|
await input.hover()
|
||||||
await select.locator('.tiny-select__caret').click()
|
await select.locator('.tiny-select__caret.icon-close').click()
|
||||||
await page.waitForTimeout(500)
|
await page.waitForTimeout(500)
|
||||||
await expect(input).toHaveValue('')
|
await expect(input).toHaveValue('')
|
||||||
await expect(model.filter({ hasText: '触发 clear 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 clear 事件' })).toHaveCount(1)
|
||||||
|
@ -42,6 +42,7 @@ test('多选事件', async ({ page }) => {
|
||||||
const option = dropdown.locator('.tiny-option')
|
const option = dropdown.locator('.tiny-option')
|
||||||
const model = page.locator('.tiny-modal')
|
const model = page.locator('.tiny-modal')
|
||||||
|
|
||||||
|
await page.waitForTimeout(500)
|
||||||
await select.click()
|
await select.click()
|
||||||
await expect(model.filter({ hasText: '触发 focus 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 focus 事件' })).toHaveCount(1)
|
||||||
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 visible-change 事件' })).toHaveCount(1)
|
||||||
|
@ -56,7 +57,6 @@ test('多选事件', async ({ page }) => {
|
||||||
|
|
||||||
await page.waitForTimeout(500)
|
await page.waitForTimeout(500)
|
||||||
await tag.first().locator('.tiny-tag__close').click()
|
await tag.first().locator('.tiny-tag__close').click()
|
||||||
await expect(model.filter({ hasText: '触发 blur 事件' })).toHaveCount(1)
|
|
||||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||||
await expect(model.filter({ hasText: '触发 remove-tag 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 remove-tag 事件' })).toHaveCount(1)
|
||||||
await expect(tag).toHaveCount(4)
|
await expect(tag).toHaveCount(4)
|
||||||
|
@ -66,7 +66,7 @@ test('多选事件', async ({ page }) => {
|
||||||
|
|
||||||
await page.waitForTimeout(200)
|
await page.waitForTimeout(200)
|
||||||
await select.hover()
|
await select.hover()
|
||||||
await select.locator('.tiny-select__caret').click()
|
await select.locator('.tiny-select__caret.icon-close').click()
|
||||||
|
|
||||||
await expect(tag).toHaveCount(0)
|
await expect(tag).toHaveCount(0)
|
||||||
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
await expect(model.filter({ hasText: '触发 change 事件' })).toHaveCount(1)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<br />
|
<br />
|
||||||
<div>场景1:多选</div>
|
<div>场景1:多选</div>
|
||||||
<br />
|
<br />
|
||||||
<tiny-select v-model="value1" multiple>
|
<tiny-select v-model="value1" multiple searchable>
|
||||||
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
<tiny-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"> </tiny-option>
|
||||||
</tiny-select>
|
</tiny-select>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -5,7 +5,7 @@ test('删除事件', async ({ page }) => {
|
||||||
await page.goto('tabs#tabs-events-close')
|
await page.goto('tabs#tabs-events-close')
|
||||||
|
|
||||||
const tabs = page.locator('.tiny-tabs')
|
const tabs = page.locator('.tiny-tabs')
|
||||||
const tabItem = tabs.getByRole('tab', { name: '表单组件' })
|
const tabItem = tabs.getByRole('tab', { name: '其他组件' })
|
||||||
const close = tabItem.locator('.tiny-tabs__icon-close')
|
const close = tabItem.locator('.tiny-tabs__icon-close')
|
||||||
const modal = page.locator('.tiny-modal').first()
|
const modal = page.locator('.tiny-modal').first()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
prettierFormat,
|
prettierFormat,
|
||||||
logGreen
|
logGreen
|
||||||
} from '../../shared/utils'
|
} from '../../shared/utils'
|
||||||
import { getComponents } from '../../shared/module-utils'
|
import { getComponents, excludeComponents } from '../../shared/module-utils'
|
||||||
import handlebarsRender from './handlebars.render'
|
import handlebarsRender from './handlebars.render'
|
||||||
|
|
||||||
const version = getopentinyVersion({ key: 'version' })
|
const version = getopentinyVersion({ key: 'version' })
|
||||||
|
@ -61,7 +61,12 @@ const buildFullRuntime = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
components.forEach((item) => {
|
components.forEach((item) => {
|
||||||
if (item.inEntry !== false && !item.path.includes('river') && !item.path.includes('chart-beta')) {
|
if (
|
||||||
|
item.inEntry !== false &&
|
||||||
|
!item.path.includes('river') &&
|
||||||
|
!item.path.includes('chart-beta') &&
|
||||||
|
!excludeComponents.includes(item.name)
|
||||||
|
) {
|
||||||
const component = capitalizeKebabCase(item.name)
|
const component = capitalizeKebabCase(item.name)
|
||||||
|
|
||||||
componentsTemplate.push(` ${component}`)
|
componentsTemplate.push(` ${component}`)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
prettierFormat,
|
prettierFormat,
|
||||||
logGreen
|
logGreen
|
||||||
} from '../../shared/utils'
|
} from '../../shared/utils'
|
||||||
import { getComponents } from '../../shared/module-utils'
|
import { getComponents, excludeComponents } from '../../shared/module-utils'
|
||||||
import handlebarsRender from './handlebars.render'
|
import handlebarsRender from './handlebars.render'
|
||||||
|
|
||||||
const version = getopentinyVersion({ key: 'version' })
|
const version = getopentinyVersion({ key: 'version' })
|
||||||
|
@ -79,7 +79,7 @@ const createEntry = (mode) => {
|
||||||
const PKGDeps = {}
|
const PKGDeps = {}
|
||||||
|
|
||||||
components.forEach((item) => {
|
components.forEach((item) => {
|
||||||
if (item.inEntry !== false) {
|
if (item.inEntry !== false && !excludeComponents.includes(item.name)) {
|
||||||
const component = capitalizeKebabCase(item.name)
|
const component = capitalizeKebabCase(item.name)
|
||||||
PKGDeps[item.importName] = 'workspace:~'
|
PKGDeps[item.importName] = 'workspace:~'
|
||||||
componentsTemplate.push(` ${component}`)
|
componentsTemplate.push(` ${component}`)
|
||||||
|
|
|
@ -160,6 +160,7 @@ export const getBaseConfig = ({ vueVersion, dtsInclude, dts, buildTarget, isRunt
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
include: [...dtsInclude, 'packages/vue/*.d.ts'],
|
include: [...dtsInclude, 'packages/vue/*.d.ts'],
|
||||||
|
exclude: ['**/__tests__'],
|
||||||
beforeWriteFile: (filePath, content) => {
|
beforeWriteFile: (filePath, content) => {
|
||||||
return {
|
return {
|
||||||
// "vue/src/alert/index.d.ts" ==> "alert/index.d.ts"
|
// "vue/src/alert/index.d.ts" ==> "alert/index.d.ts"
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
import type { Plugin, NormalizedOutputOptions, OutputBundle, OutputChunk } from 'rollup'
|
import type { Plugin, NormalizedOutputOptions, OutputBundle } from 'rollup'
|
||||||
|
import path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import { rollup } from 'rollup'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
|
import commonjs from '@rollup/plugin-commonjs'
|
||||||
|
import { external } from '../../../shared/config'
|
||||||
|
|
||||||
|
const bundlesToMerge = new Set<string>()
|
||||||
|
const commonChunk = new Set<string>()
|
||||||
|
let buildFormat
|
||||||
|
let isDelete
|
||||||
|
|
||||||
export default function ({ deleteInlinedFiles = true }): Plugin {
|
export default function ({ deleteInlinedFiles = true }): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'opentiny-vue:inline-chunks',
|
name: 'opentiny-vue:inline-chunks',
|
||||||
generateBundle: ({ format }: NormalizedOutputOptions, bundle: OutputBundle) => {
|
generateBundle: async ({ format, dir }: NormalizedOutputOptions, bundle: OutputBundle) => {
|
||||||
const bundlesToDelete = new Set<string>()
|
buildFormat = format
|
||||||
const cache = {}
|
isDelete = deleteInlinedFiles
|
||||||
|
|
||||||
const jsAssets = Object.keys(bundle).filter((i) => /\.[mc]?js$/.test(i))
|
const jsAssets = Object.keys(bundle).filter((i) => /\.[mc]?js$/.test(i))
|
||||||
for (const jsName of jsAssets) {
|
for (const jsName of jsAssets) {
|
||||||
const jsChunk = bundle[jsName]
|
const jsChunk = bundle[jsName]
|
||||||
|
@ -16,51 +25,66 @@ export default function ({ deleteInlinedFiles = true }): Plugin {
|
||||||
if (!jsChunk.code) continue
|
if (!jsChunk.code) continue
|
||||||
|
|
||||||
if (format === 'es') {
|
if (format === 'es') {
|
||||||
jsChunk.code = jsChunk.code.replace(
|
const reg = /^import(\s*.+\s*from)?\s+"[./]+(.+-[a-f0-9]{8}.+)".*$/gim
|
||||||
// import { _ as _export_sfc } from "../../../../_plugin-vue_export-helper-1faf6727.mjs"
|
const matchArr = jsChunk.code.match(reg)
|
||||||
/^import\s*.+\s*from\s+"[./]+(.+-[a-f0-9]{8}.+)".*$/gim,
|
if (matchArr) {
|
||||||
(_, chunkName) => {
|
const filePath = path.join(dir, jsName)
|
||||||
if (!cache[chunkName]) {
|
bundlesToMerge.add(filePath)
|
||||||
cache[chunkName] = (bundle[chunkName] as OutputChunk).code
|
matchArr.forEach((matchImport) => {
|
||||||
.replace(/export {[\s\S]+$/, '')
|
const sourceName = matchImport.match(/"(.+)"/)[1]
|
||||||
.replace(/_extends/g, '_extends_tiny')
|
commonChunk.add(path.join(filePath, '../', sourceName))
|
||||||
.replace(/_createForOfIteratorHelperLoose/g, '_createForOfIteratorHelperLoose_tiny')
|
})
|
||||||
.replace(/_unsupportedIterableToArray/g, '_unsupportedIterableToArray_tiny')
|
}
|
||||||
.replace(/_arrayLikeToArray/g, '_arrayLikeToArray_tiny')
|
|
||||||
bundlesToDelete.add(chunkName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache[chunkName]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === 'cjs') {
|
if (format === 'cjs') {
|
||||||
jsChunk.code = jsChunk.code.replace(
|
const reg = /require\("[./]+(.+-[a-f0-9]{8}.+)".*$/gim
|
||||||
// var _pluginVue_exportHelper = require("../../../../_plugin-vue_export-helper-65c7de93.js");
|
const matchArr = jsChunk.code.match(reg)
|
||||||
/^var\s+(.+)\s+=\s+require\("[./]+(.+-[a-f0-9]{8}.+)".*$/gim,
|
if (matchArr) {
|
||||||
(_, localVarName, chunkName) => {
|
const filePath = path.join(dir, jsName)
|
||||||
if (!cache[chunkName]) {
|
bundlesToMerge.add(filePath)
|
||||||
cache[chunkName] =
|
matchArr.forEach((matchRequire) => {
|
||||||
'var _pluginVue_exportHelper = {};\n' +
|
const sourceName = matchRequire.match(/"(.+)"/)[1]
|
||||||
(bundle[chunkName] as OutputChunk).code.replace(/exports\./g, `${localVarName}.`)
|
commonChunk.add(path.join(filePath, '../', sourceName))
|
||||||
bundlesToDelete.add(chunkName)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache[chunkName]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
if (deleteInlinedFiles) {
|
closeBundle: async () =>
|
||||||
// 删除 chunks
|
new Promise((resolve) => {
|
||||||
bundlesToDelete.forEach((name) => {
|
// eslint-disable-next-line no-console
|
||||||
delete bundle[name]
|
console.log(`\n${chalk.green('开始内联公共依赖')}`)
|
||||||
// eslint-disable-next-line no-console
|
let i = 0
|
||||||
console.log(`\n${chalk.red(name)} 已经被内联并删除`)
|
if (bundlesToMerge.size > 0) {
|
||||||
})
|
bundlesToMerge.forEach(async (filePath) => {
|
||||||
}
|
if (commonChunk.has(filePath)) {
|
||||||
}
|
++i
|
||||||
|
} else {
|
||||||
|
const bundle = await rollup({
|
||||||
|
input: filePath,
|
||||||
|
external: (source) => external(source),
|
||||||
|
plugins: buildFormat === 'cjs' ? [commonjs()] : []
|
||||||
|
})
|
||||||
|
await bundle.write({ dir: path.join(filePath, '../'), format: buildFormat })
|
||||||
|
await bundle.close()
|
||||||
|
++i
|
||||||
|
}
|
||||||
|
if (i === bundlesToMerge.size) {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}).then(async () => {
|
||||||
|
if (isDelete) {
|
||||||
|
commonChunk.forEach((filePath) => {
|
||||||
|
fs.unlinkSync(filePath)
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`\n${chalk.red(filePath)} 已经被内联并删除`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,15 +35,14 @@ const findAllpage = (packagesPath) => {
|
||||||
// 解决TinyVue和AUI国际化键名不兼容问题
|
// 解决TinyVue和AUI国际化键名不兼容问题
|
||||||
.replace(/zhCN/g, 'zh_CN')
|
.replace(/zhCN/g, 'zh_CN')
|
||||||
.replace(/enUS/g, 'en_US')
|
.replace(/enUS/g, 'en_US')
|
||||||
|
.replace(/-openaui/g, '-opentiny')
|
||||||
// 解决在linkjs环境z-index无法统一导致下拉框被遮挡问题
|
// 解决在linkjs环境z-index无法统一导致下拉框被遮挡问题
|
||||||
.replace(/"(.*?\/popup-manager)"/g, '"@aurora/renderless/common/deps/popup-manager"')
|
.replace(/"(.*?\/popup-manager)"/g, '"@aurora/renderless/common/deps/popup-manager"')
|
||||||
|
|
||||||
// 解决当AUI只有一个mobile-first模板而TinyVue有多个模板,导致Linkjs加载不到多端模板的问题
|
// 解决当AUI只有一个mobile-first模板而TinyVue有多个模板,导致Linkjs加载不到多端模板的问题
|
||||||
if (
|
if (
|
||||||
packagesPath.endsWith('index.js') &&
|
packagesPath.endsWith('index.js') &&
|
||||||
onlyMobileFirstTemplateLists.some(
|
onlyMobileFirstTemplateLists.some((item) => packagesPath.includes(`${path.sep}${item}${path.sep}`))
|
||||||
(item) => packagesPath.includes(`${item}\\`) || packagesPath.includes(`${item}/`)
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
result = result.replace(/pc.js/g, 'mobile-first.js')
|
result = result.replace(/pc.js/g, 'mobile-first.js')
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ const moduleMap = require(pathFromWorkspaceRoot('packages/modules.json'))
|
||||||
|
|
||||||
type mode = 'pc' | 'mobile' | 'mobile-first'
|
type mode = 'pc' | 'mobile' | 'mobile-first'
|
||||||
|
|
||||||
|
// 需要在入口文件中排除的组件,比如:富文本
|
||||||
|
export const excludeComponents = ['RichText']
|
||||||
|
|
||||||
export interface Module {
|
export interface Module {
|
||||||
/** 源码路径,如 vue/src/button/index.ts */
|
/** 源码路径,如 vue/src/button/index.ts */
|
||||||
path: string
|
path: string
|
||||||
|
@ -452,8 +455,7 @@ const createModuleMapping = (componentName, isMobile = false) => {
|
||||||
parser: 'json',
|
parser: 'json',
|
||||||
printWidth: 10
|
printWidth: 10
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ export default {
|
||||||
medium: 42
|
medium: 42
|
||||||
},
|
},
|
||||||
spacingHeight: 2,
|
spacingHeight: 2,
|
||||||
initialInputHeight: 30
|
initialInputHeight: 30,
|
||||||
|
// 显示清除等图标时,不隐藏下拉箭头时
|
||||||
|
autoHideDownIcon: false
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
tagType: 'info'
|
tagType: 'info'
|
||||||
|
|
|
@ -14,7 +14,9 @@ export default {
|
||||||
medium: 32
|
medium: 32
|
||||||
},
|
},
|
||||||
spacingHeight: 4,
|
spacingHeight: 4,
|
||||||
initialInputHeight: 30
|
initialInputHeight: 30,
|
||||||
|
// 显示清除等图标时,不隐藏下拉箭头时
|
||||||
|
autoHideDownIcon: false
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
tagType: 'info'
|
tagType: 'info'
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { iconPutAway, iconExpand } from '@opentiny/vue-icon'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
icons: {
|
icons: {
|
||||||
|
// 在 showLine=true时,才要切换的图标。 并不是设置正常模式下的图标
|
||||||
expanded: iconExpand(),
|
expanded: iconExpand(),
|
||||||
collapse: iconPutAway()
|
collapse: iconPutAway()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2360,6 +2360,14 @@
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"exclude": false
|
"exclude": false
|
||||||
},
|
},
|
||||||
|
"RichText": {
|
||||||
|
"path": "vue/src/rich-text/index.ts",
|
||||||
|
"type": "component",
|
||||||
|
"exclude": false,
|
||||||
|
"mode": [
|
||||||
|
"pc"
|
||||||
|
]
|
||||||
|
},
|
||||||
"RichTextEditor": {
|
"RichTextEditor": {
|
||||||
"path": "vue/src/rich-text-editor/index.ts",
|
"path": "vue/src/rich-text-editor/index.ts",
|
||||||
"type": "component",
|
"type": "component",
|
||||||
|
|
|
@ -180,7 +180,7 @@ export class BigIntDecimal {
|
||||||
const convertBigInt = (str) => {
|
const convertBigInt = (str) => {
|
||||||
// 将以多个零开头的整数前置零清空 '0000000000000003e+21' --> '3e+21' ,解决BigInt(0000000000000003e+21)报错问题
|
// 将以多个零开头的整数前置零清空 '0000000000000003e+21' --> '3e+21' ,解决BigInt(0000000000000003e+21)报错问题
|
||||||
const validStr = str.replace(/^0+/, '') || '0'
|
const validStr = str.replace(/^0+/, '') || '0'
|
||||||
return f(`return BigInt(${validStr})`)()
|
return f(`return BigInt('${validStr}')`)()
|
||||||
}
|
}
|
||||||
if (validateNumber(mergedValue)) {
|
if (validateNumber(mergedValue)) {
|
||||||
const trimRet = trimNumber(mergedValue)
|
const trimRet = trimNumber(mergedValue)
|
||||||
|
@ -188,7 +188,9 @@ export class BigIntDecimal {
|
||||||
const numbers = trimRet.trimStr.split('.')
|
const numbers = trimRet.trimStr.split('.')
|
||||||
this.integer = !numbers[0].includes('e') ? BigInt(numbers[0]) : numbers[0]
|
this.integer = !numbers[0].includes('e') ? BigInt(numbers[0]) : numbers[0]
|
||||||
const decimalStr = numbers[1] || '0'
|
const decimalStr = numbers[1] || '0'
|
||||||
this.decimal = convertBigInt(decimalStr)
|
|
||||||
|
// 如果小数点后有科学计数法,需要特殊处理,如果是正常数字则保留之前逻辑
|
||||||
|
this.decimal = decimalStr.includes('e') ? convertBigInt(decimalStr) : BigInt(decimalStr)
|
||||||
this.decimalLen = decimalStr.length
|
this.decimalLen = decimalStr.length
|
||||||
} else {
|
} else {
|
||||||
this.nan = true
|
this.nan = true
|
||||||
|
|
|
@ -91,11 +91,13 @@ export const prevDate = (date, amount = 1) => new Date(date.getFullYear(), date.
|
||||||
|
|
||||||
export const nextDate = (date, amount = 1) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount)
|
export const nextDate = (date, amount = 1) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount)
|
||||||
|
|
||||||
export const getStartDateOfMonth = (year, month) => {
|
export const getStartDateOfMonth = (year, month, offsetDay = 0) => {
|
||||||
const res = new Date(year, month, 1)
|
const res = new Date(year, month, 1)
|
||||||
const day = res.getDay()
|
const day = res.getDay()
|
||||||
|
const _day = day === 0 ? 7 : day
|
||||||
|
|
||||||
return day === 0 ? prevDate(res, 7) : prevDate(res, day)
|
const offset = _day + offsetDay <= 0 ? 7 + _day : _day
|
||||||
|
return prevDate(res, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getWeekNumber = (src) => {
|
export const getWeekNumber = (src) => {
|
||||||
|
@ -143,6 +145,7 @@ const setRangeData = (arr, start, end, value) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line prefer-spread
|
||||||
export const range = (length) => Array.apply(null, { length }).map((_, n) => n)
|
export const range = (length) => Array.apply(null, { length }).map((_, n) => n)
|
||||||
|
|
||||||
export const getMonthDays = (date) => {
|
export const getMonthDays = (date) => {
|
||||||
|
|
|
@ -207,6 +207,7 @@ export const handleClear =
|
||||||
state.leftDate = calcDefaultValue(state.defaultValue)[0]
|
state.leftDate = calcDefaultValue(state.defaultValue)[0]
|
||||||
state.rightDate = nextMonth(state.leftDate)
|
state.rightDate = nextMonth(state.leftDate)
|
||||||
state.rangeState.selecting = false
|
state.rangeState.selecting = false
|
||||||
|
// tiny 新增下面行
|
||||||
state.rangeState.endDate = null
|
state.rangeState.endDate = null
|
||||||
|
|
||||||
emit('pick', null)
|
emit('pick', null)
|
||||||
|
|
|
@ -127,6 +127,7 @@ const initState = ({ reactive, computed, api, constants, designConfig }) => {
|
||||||
dateFormat: computed(() => (state.format ? extractDateFormat(state.format) : 'yyyy-MM-dd')),
|
dateFormat: computed(() => (state.format ? extractDateFormat(state.format) : 'yyyy-MM-dd')),
|
||||||
enableMonthArrow: computed(() => api.getEnableMonthArrow()),
|
enableMonthArrow: computed(() => api.getEnableMonthArrow()),
|
||||||
enableYearArrow: computed(() => api.computerEnableYearArrow()),
|
enableYearArrow: computed(() => api.computerEnableYearArrow()),
|
||||||
|
// tiny 新增
|
||||||
confirmButtonProps: {
|
confirmButtonProps: {
|
||||||
plain: true,
|
plain: true,
|
||||||
type: 'default',
|
type: 'default',
|
||||||
|
|
|
@ -21,10 +21,9 @@ import {
|
||||||
clearTime
|
clearTime
|
||||||
} from '../common/deps/date-util'
|
} from '../common/deps/date-util'
|
||||||
import { DATEPICKER } from '../common'
|
import { DATEPICKER } from '../common'
|
||||||
import type { IDateTableRow } from '@/types'
|
|
||||||
|
|
||||||
const formatJudg = ({ day, offset, j, i, cell, count, dateCountOfLastMonth }) => {
|
const formatJudg = ({ day, offset, j, i, cell, count, dateCountOfLastMonth }) => {
|
||||||
const nodfpm = day + offset < 0 ? 7 + day + offset : day + offset
|
const nodfpm = day + offset <= 0 ? 7 + day + offset : day + offset
|
||||||
|
|
||||||
if (j + i * 7 >= nodfpm) {
|
if (j + i * 7 >= nodfpm) {
|
||||||
cell.text = count++
|
cell.text = count++
|
||||||
|
@ -58,22 +57,8 @@ export const getDateTimestamp = (time) => {
|
||||||
return NaN
|
return NaN
|
||||||
}
|
}
|
||||||
|
|
||||||
export const arrayFindIndex = (arr, pred) => {
|
// tiny 新增: api参数多余,优化掉
|
||||||
for (let i = 0, len = arr.length; i !== len; ++i) {
|
const getSelected = (props, cell, format, t, cellDate, selectedDate) => {
|
||||||
if (pred(arr[i])) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
export const arrayFind = (arr, pred) => {
|
|
||||||
const idx = arrayFindIndex(arr, pred)
|
|
||||||
return ~idx ? arr[idx] : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSelected = ({ props, cell, format, t, cellDate, selectedDate }) => {
|
|
||||||
let selected = cell.selected
|
let selected = cell.selected
|
||||||
|
|
||||||
if (props.selectionMode === 'dates') {
|
if (props.selectionMode === 'dates') {
|
||||||
|
@ -92,14 +77,7 @@ export const getCell =
|
||||||
let cell = row[props.showWeekNumber ? j + 1 : j]
|
let cell = row[props.showWeekNumber ? j + 1 : j]
|
||||||
|
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
cell = {
|
cell = { row: i, column: j, inRange: false, start: false, end: false, type: DATEPICKER.Normal }
|
||||||
row: i,
|
|
||||||
column: j,
|
|
||||||
inRange: false,
|
|
||||||
start: false,
|
|
||||||
end: false,
|
|
||||||
type: DATEPICKER.Normal
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.type = DATEPICKER.Normal
|
cell.type = DATEPICKER.Normal
|
||||||
|
@ -119,15 +97,7 @@ export const getCell =
|
||||||
|
|
||||||
const doCount = ({ i, day, offset, j, cell, count, dateCountOfLastMonth, dateCountOfMonth }) => {
|
const doCount = ({ i, day, offset, j, cell, count, dateCountOfLastMonth, dateCountOfMonth }) => {
|
||||||
if (i >= 0 && i <= 1) {
|
if (i >= 0 && i <= 1) {
|
||||||
const ret = formatJudg({
|
const ret = formatJudg({ day, offset, j, i, cell, count, dateCountOfLastMonth })
|
||||||
day,
|
|
||||||
offset,
|
|
||||||
j,
|
|
||||||
i,
|
|
||||||
cell,
|
|
||||||
count,
|
|
||||||
dateCountOfLastMonth
|
|
||||||
})
|
|
||||||
count = ret.count
|
count = ret.count
|
||||||
} else {
|
} else {
|
||||||
if (count <= dateCountOfMonth) {
|
if (count <= dateCountOfMonth) {
|
||||||
|
@ -141,8 +111,6 @@ const doCount = ({ i, day, offset, j, cell, count, dateCountOfLastMonth, dateCou
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
export const coerceTruthyValueToArray = (val) => (Array.isArray(val) ? val : val ? [val] : [])
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取日期表格二维数组,用于渲染日期表格。
|
* 获取日期表格二维数组,用于渲染日期表格。
|
||||||
*
|
*
|
||||||
|
@ -160,7 +128,7 @@ export const coerceTruthyValueToArray = (val) => (Array.isArray(val) ? val : val
|
||||||
*/
|
*/
|
||||||
export const getRows =
|
export const getRows =
|
||||||
({ api, props, state, t, vm }) =>
|
({ api, props, state, t, vm }) =>
|
||||||
(): IDateTableRow[][] => {
|
() => {
|
||||||
const date = new Date(state.year, state.month, 1)
|
const date = new Date(state.year, state.month, 1)
|
||||||
let day = getFirstDayOfMonth(date)
|
let day = getFirstDayOfMonth(date)
|
||||||
const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth())
|
const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth())
|
||||||
|
@ -172,7 +140,7 @@ export const getRows =
|
||||||
day = day === 0 ? 7 : day
|
day = day === 0 ? 7 : day
|
||||||
|
|
||||||
const offset = state.offsetDay
|
const offset = state.offsetDay
|
||||||
const rows: IDateTableRow[][] = state.tableRows
|
const rows = state.tableRows
|
||||||
const startDate = state.startDate
|
const startDate = state.startDate
|
||||||
const disabledDate = props.disabledDate
|
const disabledDate = props.disabledDate
|
||||||
const cellClassName = props.cellClassName
|
const cellClassName = props.cellClassName
|
||||||
|
@ -181,7 +149,7 @@ export const getRows =
|
||||||
|
|
||||||
const isFunction = props.formatWeeks instanceof Function
|
const isFunction = props.formatWeeks instanceof Function
|
||||||
|
|
||||||
const arr: Date[][] = []
|
const arr = []
|
||||||
|
|
||||||
// 日期表格行,从0开始,共6行,[0, 5]
|
// 日期表格行,从0开始,共6行,[0, 5]
|
||||||
for (let i = 0; i < 6; i++) {
|
for (let i = 0; i < 6; i++) {
|
||||||
|
@ -207,15 +175,7 @@ export const getRows =
|
||||||
count = doCount({ i, day, offset, j, cell, count, dateCountOfLastMonth, dateCountOfMonth })
|
count = doCount({ i, day, offset, j, cell, count, dateCountOfLastMonth, dateCountOfMonth })
|
||||||
|
|
||||||
cell.disabled = typeof disabledDate === 'function' && disabledDate(cellDate)
|
cell.disabled = typeof disabledDate === 'function' && disabledDate(cellDate)
|
||||||
cell.selected = getSelected({
|
cell.selected = getSelected(props, cell, DATEPICKER.DateFormats.date, t, cellDate, selectedDate)
|
||||||
props,
|
|
||||||
cell,
|
|
||||||
api,
|
|
||||||
format: DATEPICKER.DateFormats.date,
|
|
||||||
t,
|
|
||||||
cellDate,
|
|
||||||
selectedDate
|
|
||||||
})
|
|
||||||
cell.customClass = typeof cellClassName === 'function' && cellClassName(cellDate)
|
cell.customClass = typeof cellClassName === 'function' && cellClassName(cellDate)
|
||||||
|
|
||||||
// 更新日期表格的行数据,执行了这行代码,rows 中才会有数据
|
// 更新日期表格的行数据,执行了这行代码,rows 中才会有数据
|
||||||
|
@ -250,6 +210,23 @@ export const getRows =
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const arrayFindIndex = (arr, pred) => {
|
||||||
|
for (let i = 0, len = arr.length; i !== len; ++i) {
|
||||||
|
if (pred(arr[i])) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
export const arrayFind = (arr, pred) => {
|
||||||
|
const idx = arrayFindIndex(arr, pred)
|
||||||
|
return ~idx ? arr[idx] : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export const coerceTruthyValueToArray = (val) => (Array.isArray(val) ? val : val ? [val] : [])
|
||||||
|
|
||||||
export const watchMinDate =
|
export const watchMinDate =
|
||||||
({ api, props }) =>
|
({ api, props }) =>
|
||||||
(value, oldvalue) => {
|
(value, oldvalue) => {
|
||||||
|
@ -398,15 +375,15 @@ export const markRange =
|
||||||
const row = rows[i]
|
const row = rows[i]
|
||||||
|
|
||||||
for (let j = 0, l = row.length; j < l; j++) {
|
for (let j = 0, l = row.length; j < l; j++) {
|
||||||
if (!props.showWeekNumber || j !== 0) {
|
if (props.showWeekNumber && j === 0) continue
|
||||||
const cell = row[j]
|
|
||||||
const index = i * 7 + j + (props.showWeekNumber ? -1 : 0)
|
|
||||||
const time = nextDate(startDate, index - state.offsetDay).getTime()
|
|
||||||
|
|
||||||
cell.inRange = minDate && time >= minDate && time <= maxDate
|
const cell = row[j]
|
||||||
cell.start = minDate && time === minDate
|
const index = i * 7 + j + (props.showWeekNumber ? -1 : 0)
|
||||||
cell.end = maxDate && time === maxDate
|
const time = nextDate(startDate, index - state.offsetDay).getTime()
|
||||||
}
|
|
||||||
|
cell.inRange = minDate && time >= minDate && time <= maxDate
|
||||||
|
cell.start = minDate && time === minDate
|
||||||
|
cell.end = maxDate && time === maxDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,12 +445,6 @@ const getTarget = (event) => {
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
export const removeFromArray = (arr, pred) => {
|
|
||||||
const idx = typeof pred === 'function' ? arrayFindIndex(arr, pred) : arr.indexOf(pred)
|
|
||||||
|
|
||||||
return idx >= 0 ? [...arr.slice(0, idx), ...arr.slice(idx + 1)] : arr
|
|
||||||
}
|
|
||||||
|
|
||||||
export const handleClick =
|
export const handleClick =
|
||||||
({ api, emit, props, state }) =>
|
({ api, emit, props, state }) =>
|
||||||
(event) => {
|
(event) => {
|
||||||
|
@ -529,8 +500,16 @@ export const handleClick =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCssToken = ({ api }) => (cell, prexfix = '') => {
|
export const removeFromArray = (arr, pred) => {
|
||||||
const cssStr = api.getCellClasses(cell) || ''
|
const idx = typeof pred === 'function' ? arrayFindIndex(arr, pred) : arr.indexOf(pred)
|
||||||
|
|
||||||
return cssStr.split(' ').map((className) => prexfix + className)
|
return idx >= 0 ? [...arr.slice(0, idx), ...arr.slice(idx + 1)] : arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getCssToken =
|
||||||
|
({ api }) =>
|
||||||
|
(cell, prexfix = '') => {
|
||||||
|
const cssStr = api.getCellClasses(cell) || ''
|
||||||
|
|
||||||
|
return cssStr.split(' ').map((className) => prexfix + className)
|
||||||
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ const initState = ({ reactive, computed, api, props }) => {
|
||||||
month: computed(() => !Array.isArray(props.date) && props.date.getMonth()),
|
month: computed(() => !Array.isArray(props.date) && props.date.getMonth()),
|
||||||
offsetDay: computed(() => api.getOffsetDay()),
|
offsetDay: computed(() => api.getOffsetDay()),
|
||||||
year: computed(() => !Array.isArray(props.date) && props.date.getFullYear()),
|
year: computed(() => !Array.isArray(props.date) && props.date.getFullYear()),
|
||||||
startDate: computed(() => getStartDateOfMonth(state.year, state.month)),
|
startDate: computed(() => getStartDateOfMonth(state.year, state.month, state.offsetDay)),
|
||||||
date: props.value
|
date: props.value
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,10 @@ export const increase =
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = (props.mouseWheel ? state.displayValue : Number(state.userInput)) || 0
|
// 处理高精度情况
|
||||||
|
const userInput = props.stringMode ? state.userInput : Number(state.userInput)
|
||||||
|
|
||||||
|
const value = (props.mouseWheel ? state.displayValue : userInput) || 0
|
||||||
|
|
||||||
if (value.toString().includes('e')) {
|
if (value.toString().includes('e')) {
|
||||||
return
|
return
|
||||||
|
@ -142,7 +145,11 @@ export const decrease =
|
||||||
if (state.inputDisabled || state.minDisabled) {
|
if (state.inputDisabled || state.minDisabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const value = (props.mouseWheel ? state.displayValue : Number(state.userInput)) || 0
|
|
||||||
|
// 处理高精度情况
|
||||||
|
const userInput = props.stringMode ? state.userInput : Number(state.userInput)
|
||||||
|
|
||||||
|
const value = (props.mouseWheel ? state.displayValue : userInput) || 0
|
||||||
|
|
||||||
if (value.toString().includes('e')) {
|
if (value.toString().includes('e')) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -16,7 +16,6 @@ import userPopper from '../common/deps/vue-popper'
|
||||||
import { DATEPICKER } from '../common'
|
import { DATEPICKER } from '../common'
|
||||||
import { formatDate, parseDate, isDateObject, getWeekNumber, prevDate, nextDate } from '../common/deps/date-util'
|
import { formatDate, parseDate, isDateObject, getWeekNumber, prevDate, nextDate } from '../common/deps/date-util'
|
||||||
import { extend } from '../common/object'
|
import { extend } from '../common/object'
|
||||||
import { isFunction } from '../common/type'
|
|
||||||
import globalTimezone from './timezone'
|
import globalTimezone from './timezone'
|
||||||
|
|
||||||
const iso8601Reg = /^\d{4}-\d{2}-\d{2}(.)\d{2}:\d{2}:\d{2}(.+)$/
|
const iso8601Reg = /^\d{4}-\d{2}-\d{2}(.)\d{2}:\d{2}:\d{2}(.+)$/
|
||||||
|
@ -41,8 +40,18 @@ export const getPanel =
|
||||||
return DatePanel
|
return DatePanel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const watchMobileVisible =
|
||||||
|
({ api, props, state }) =>
|
||||||
|
([dateMobileVisible, timeMobileVisible]) => {
|
||||||
|
if (dateMobileVisible || timeMobileVisible) {
|
||||||
|
state.valueOnOpen = Array.isArray(props.modelValue) ? [...props.modelValue] : props.modelValue
|
||||||
|
} else {
|
||||||
|
api.emitChange(props.modelValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const watchPickerVisible =
|
export const watchPickerVisible =
|
||||||
({ api, vm, dispatch, emit, props, state }) =>
|
({ api, vm, dispatch, emit, props, state, nextTick }) =>
|
||||||
(value) => {
|
(value) => {
|
||||||
if (props.readonly || state.pickerDisabled || state.isMobileScreen) return
|
if (props.readonly || state.pickerDisabled || state.isMobileScreen) return
|
||||||
|
|
||||||
|
@ -52,15 +61,18 @@ export const watchPickerVisible =
|
||||||
state.valueOnOpen = Array.isArray(props.modelValue) ? [...props.modelValue] : props.modelValue
|
state.valueOnOpen = Array.isArray(props.modelValue) ? [...props.modelValue] : props.modelValue
|
||||||
} else {
|
} else {
|
||||||
api.hidePicker()
|
api.hidePicker()
|
||||||
api.emitChange(props.modelValue)
|
// tiny 新增: 解决vue3下,modelValue的值仍是旧值,误认为值不变,不触发change事件了。
|
||||||
|
nextTick(() => api.emitChange(props.modelValue))
|
||||||
state.userInput = null
|
state.userInput = null
|
||||||
|
|
||||||
if (props.validateEvent) {
|
if (props.validateEvent) {
|
||||||
dispatch('FormItem', 'form.blur')
|
dispatch('FormItem', 'form.blur')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.changeOnConfirm && !valueEquals(props.modelValue, state.oldValue)) {
|
if (props.changeOnConfirm && !valueEquals(props.modelValue, state.oldValue)) {
|
||||||
emit('update:modelValue', state.oldValue)
|
emit('update:modelValue', state.oldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('blur', vm)
|
emit('blur', vm)
|
||||||
api.blur()
|
api.blur()
|
||||||
}
|
}
|
||||||
|
@ -117,14 +129,8 @@ export const displayValue =
|
||||||
const formatObj = {
|
const formatObj = {
|
||||||
rangeSeparator: props.rangeSeparator
|
rangeSeparator: props.rangeSeparator
|
||||||
}
|
}
|
||||||
const formattedValue = api.formatAsFormatAndType(
|
|
||||||
state.parsedValue,
|
|
||||||
state.format,
|
|
||||||
state.type,
|
|
||||||
props.rangeSeparator,
|
|
||||||
formatObj
|
|
||||||
)
|
|
||||||
|
|
||||||
|
const formattedValue = api.formatAsFormatAndType(state.parsedValue, state.format, state.type, formatObj)
|
||||||
if (Array.isArray(state.userInput)) {
|
if (Array.isArray(state.userInput)) {
|
||||||
return [
|
return [
|
||||||
state.userInput[0] || (formattedValue && formattedValue[0]) || '',
|
state.userInput[0] || (formattedValue && formattedValue[0]) || '',
|
||||||
|
@ -176,12 +182,13 @@ export const parsedValue =
|
||||||
|
|
||||||
if (isServiceTimezone) {
|
if (isServiceTimezone) {
|
||||||
if (Array.isArray(date)) {
|
if (Array.isArray(date)) {
|
||||||
date = [].concat(date).map((item) => (isDate(item) ? formatDate(item, state.valueFormat, t) : item))
|
date = [].concat(date).map((item) => {
|
||||||
|
return isDate(item) ? formatDate(item, state.valueFormat, t) : item
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
date = formatDate(date, state.valueFormat, t)
|
date = formatDate(date, state.valueFormat, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = api.parseAsFormatAndType(date, state.valueFormat, state.type, props.rangeSeparator)
|
const result = api.parseAsFormatAndType(date, state.valueFormat, state.type, props.rangeSeparator)
|
||||||
if (Array.isArray(result)) {
|
if (Array.isArray(result)) {
|
||||||
return result.map((date) => getDateWithNewTimezone(date, from, to, timezoneOffset))
|
return result.map((date) => getDateWithNewTimezone(date, from, to, timezoneOffset))
|
||||||
|
@ -194,7 +201,6 @@ export const parsedValue =
|
||||||
const values = []
|
const values = []
|
||||||
.concat(props.modelValue)
|
.concat(props.modelValue)
|
||||||
.map((val) => getDateWithNewTimezone(trans(val), from, to, timezoneOffset))
|
.map((val) => getDateWithNewTimezone(trans(val), from, to, timezoneOffset))
|
||||||
|
|
||||||
return values.length > 1 ? values : values[0]
|
return values.length > 1 ? values : values[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +343,6 @@ const getWeekOfTypeValueResolveMap = ({ t, props, api }) => ({
|
||||||
trueDate.setHours(0, 0, 0, 0)
|
trueDate.setHours(0, 0, 0, 0)
|
||||||
trueDate.setDate(trueDate.getDate() + 3 - ((trueDate.getDay() + 6) % 7))
|
trueDate.setDate(trueDate.getDate() + 3 - ((trueDate.getDay() + 6) % 7))
|
||||||
}
|
}
|
||||||
|
|
||||||
let date
|
let date
|
||||||
if (type === 'format' && !/W/.test(format)) {
|
if (type === 'format' && !/W/.test(format)) {
|
||||||
const { start, end } = getWeekRange(value, format, t, props.pickerOptions)
|
const { start, end } = getWeekRange(value, format, t, props.pickerOptions)
|
||||||
|
@ -346,6 +351,7 @@ const getWeekOfTypeValueResolveMap = ({ t, props, api }) => ({
|
||||||
date = formatDate(trueDate, format, t)
|
date = formatDate(trueDate, format, t)
|
||||||
date = /WW/.test(date) ? date.replace(/WW/, week < 10 ? '0' + week : week) : date.replace(/W/, week)
|
date = /WW/.test(date) ? date.replace(/WW/, week < 10 ? '0' + week : week) : date.replace(/W/, week)
|
||||||
}
|
}
|
||||||
|
|
||||||
return date
|
return date
|
||||||
},
|
},
|
||||||
parser(text, format) {
|
parser(text, format) {
|
||||||
|
@ -505,12 +511,211 @@ export const handleMouseEnter =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 这个是 input 组件的 input 事件,应该只有一个 event 参数,input 组件的具体值从 event.target.value 中获取。
|
||||||
|
export const handleInput =
|
||||||
|
({ state, props, api }) =>
|
||||||
|
(val, event) => {
|
||||||
|
// 兼容tiny-input传参不同导致的报错问题
|
||||||
|
event = val.target ? val : event
|
||||||
|
if (props.autoFormat) {
|
||||||
|
const value = api.formatInputValue({ event, prevValue: state.displayValue })
|
||||||
|
state.userInput = value
|
||||||
|
} else {
|
||||||
|
const val = event.target.value
|
||||||
|
state.userInput = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatInputValue =
|
||||||
|
({ props, state }) =>
|
||||||
|
({ event, prevValue = '' }) => {
|
||||||
|
const val = event.target.value
|
||||||
|
const inputData = event.data
|
||||||
|
const format = state.type === 'time-select' ? 'HH:mm' : props.format || DATEPICKER.DateFormats[state.type]
|
||||||
|
if (inputData && inputData.charCodeAt() >= 48 && inputData.charCodeAt() <= 57) {
|
||||||
|
return formatText({ event, format, text: prevValue, needSelectionStart: true })
|
||||||
|
} else {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectionStart = ({ value, format, regx, event }) => {
|
||||||
|
const formatMatchArr = format.match(regx)
|
||||||
|
let selectionStart = getSelectionStartIndex(event)
|
||||||
|
let I = 0
|
||||||
|
|
||||||
|
if (value !== '') {
|
||||||
|
const match = value.match(/[0-9]/g)
|
||||||
|
I = match === null ? 0 : match.length
|
||||||
|
|
||||||
|
for (let i = 0; i < formatMatchArr.length; i++) {
|
||||||
|
I -= Math.max(formatMatchArr[i].length, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
I = I >= 0 ? 1 : 0
|
||||||
|
I === 1 && selectionStart >= value.length && (selectionStart = value.length - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { selectionStart, I }
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNum = (value, format, regx) => {
|
||||||
|
let len = value.length
|
||||||
|
if (format && regx) {
|
||||||
|
const formatMatchArr = format.match(regx)
|
||||||
|
len = Math.max(len, formatMatchArr.join('').length)
|
||||||
|
}
|
||||||
|
let num = { str: '', arr: [] }
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let char = value.charAt(i) ? value.charAt(i) : '00'
|
||||||
|
|
||||||
|
if (/[0-9]/.test(char)) {
|
||||||
|
num.str += char
|
||||||
|
} else {
|
||||||
|
num.arr[i] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectionStartIndex = (event) => {
|
||||||
|
const inputElem = event.target
|
||||||
|
return inputElem.selectionStart - (event.data ? event.data.length : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveStart = (inputElem, moveStartIndex) => {
|
||||||
|
if (inputElem.setSelectionRange) {
|
||||||
|
inputElem.focus()
|
||||||
|
setTimeout(() => {
|
||||||
|
inputElem.setSelectionRange(moveStartIndex, moveStartIndex)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatText = ({ event, text, format, needSelectionStart = false }) => {
|
||||||
|
if (!format) return text
|
||||||
|
let cursorOffset = 0
|
||||||
|
let value = ''
|
||||||
|
let regx = /yyyy|yyy|yy|y|MM|M|dd|d|HH|hh|H|h|mm|m|ss|s|WW|W|w/g
|
||||||
|
let startIndex = 0
|
||||||
|
let { numStr, selectionStart } = getNumAndSelectionStart({
|
||||||
|
value: text,
|
||||||
|
format,
|
||||||
|
regx,
|
||||||
|
event,
|
||||||
|
needSelectionStart
|
||||||
|
})
|
||||||
|
|
||||||
|
let matchResult = regx.exec(format)
|
||||||
|
while (numStr.str !== '' && matchResult !== null) {
|
||||||
|
let subStr
|
||||||
|
let newNum
|
||||||
|
let subLen
|
||||||
|
const endIndex = matchResult.index
|
||||||
|
if (startIndex >= 0) {
|
||||||
|
value += format.substring(startIndex, endIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionStart >= startIndex + cursorOffset &&
|
||||||
|
selectionStart <= endIndex + cursorOffset &&
|
||||||
|
(selectionStart = selectionStart + endIndex - startIndex)
|
||||||
|
|
||||||
|
startIndex = regx.lastIndex
|
||||||
|
subLen = startIndex - endIndex
|
||||||
|
|
||||||
|
subStr = numStr.str.substring(0, subLen)
|
||||||
|
|
||||||
|
const firstMatchChar = matchResult[0].charAt(0)
|
||||||
|
const firstChar = parseInt(subStr.charAt(0), 10)
|
||||||
|
|
||||||
|
if (numStr.str.length > 1) {
|
||||||
|
const secondChar = numStr.str.charAt(1)
|
||||||
|
newNum = 10 * firstChar + parseInt(secondChar, 10)
|
||||||
|
} else {
|
||||||
|
newNum = firstChar
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
numStr.arr[endIndex + 1] ||
|
||||||
|
(firstMatchChar === 'M' && newNum > 12) ||
|
||||||
|
(firstMatchChar === 'd' && newNum > 31) ||
|
||||||
|
(['H', 'h'].includes(firstMatchChar) && newNum > 23) ||
|
||||||
|
('ms'.includes(firstMatchChar) && newNum > 59)
|
||||||
|
) {
|
||||||
|
subStr = matchResult[0].length === 2 ? '0' + firstChar : firstChar
|
||||||
|
selectionStart++
|
||||||
|
} else {
|
||||||
|
if (subLen === 1) {
|
||||||
|
subStr = String(newNum)
|
||||||
|
subLen++
|
||||||
|
cursorOffset++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value += subStr
|
||||||
|
numStr.str = numStr.str.substring(subLen)
|
||||||
|
matchResult = regx.exec(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { value: val, selectionStart: cursorPos } = checkFormat({
|
||||||
|
value,
|
||||||
|
format,
|
||||||
|
startIndex,
|
||||||
|
selectionStart,
|
||||||
|
regx,
|
||||||
|
needSelectionStart
|
||||||
|
})
|
||||||
|
value = val
|
||||||
|
selectionStart = cursorPos
|
||||||
|
|
||||||
|
needSelectionStart && moveStart(event.target, selectionStart)
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNumAndSelectionStart = ({ value, format, regx, event, needSelectionStart }) => {
|
||||||
|
if (needSelectionStart) {
|
||||||
|
let { selectionStart, I } = getSelectionStart({ value, format, regx, event })
|
||||||
|
let valueStr
|
||||||
|
|
||||||
|
if (event.data) {
|
||||||
|
valueStr = value.substring(0, selectionStart) + event.data + value.substring(selectionStart + I)
|
||||||
|
selectionStart++
|
||||||
|
} else {
|
||||||
|
valueStr = value
|
||||||
|
}
|
||||||
|
|
||||||
|
const numStr = getNum(valueStr)
|
||||||
|
|
||||||
|
return { numStr, selectionStart }
|
||||||
|
} else {
|
||||||
|
const numStr = getNum(value, format, regx)
|
||||||
|
return { numStr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkFormat = ({ value, format, startIndex, selectionStart, regx, needSelectionStart }) => {
|
||||||
|
if (
|
||||||
|
(!needSelectionStart && regx.lastIndex === 0) ||
|
||||||
|
(needSelectionStart && regx.lastIndex === 0 && selectionStart >= startIndex)
|
||||||
|
) {
|
||||||
|
const subFormat = `(?<=${format.substring(0, startIndex)})(\\s*\\S*\\s*)+`
|
||||||
|
const pattern = new RegExp(subFormat, 'g')
|
||||||
|
|
||||||
|
const res = format.match(pattern)
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
value += res[0]
|
||||||
|
selectionStart = value.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { value, selectionStart }
|
||||||
|
}
|
||||||
|
|
||||||
export const handleChange =
|
export const handleChange =
|
||||||
({ api, state }) =>
|
({ api, state }) =>
|
||||||
() => {
|
() => {
|
||||||
if (state.userInput) {
|
if (state.userInput) {
|
||||||
const value = api.parseString(state.displayValue)
|
const value = api.parseString(state.displayValue)
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
state.picker.state.value = value
|
state.picker.state.value = value
|
||||||
|
|
||||||
|
@ -534,6 +739,7 @@ export const handleStartInput =
|
||||||
const value = props.autoFormat
|
const value = props.autoFormat
|
||||||
? api.formatInputValue({ event, prevValue: state.displayValue[0] })
|
? api.formatInputValue({ event, prevValue: state.displayValue[0] })
|
||||||
: event.target.value
|
: event.target.value
|
||||||
|
|
||||||
if (state.userInput) {
|
if (state.userInput) {
|
||||||
state.userInput = [value, state.userInput[1]]
|
state.userInput = [value, state.userInput[1]]
|
||||||
} else {
|
} else {
|
||||||
|
@ -754,15 +960,12 @@ export const handleKeydown =
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hidePicker =
|
export const hidePicker =
|
||||||
({ state, doDestroy }) =>
|
({ destroyPopper, state }) =>
|
||||||
() => {
|
() => {
|
||||||
if (state.picker) {
|
if (state.picker) {
|
||||||
state.picker.resetView && state.picker.resetView()
|
state.picker.resetView && state.picker.resetView()
|
||||||
state.pickerVisible = state.picker.visible = state.picker.state.visible = false
|
state.pickerVisible = state.picker.visible = state.picker.state.visible = false
|
||||||
|
destroyPopper()
|
||||||
if (isFunction(doDestroy)) {
|
|
||||||
doDestroy()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,7 +983,7 @@ export const showPicker =
|
||||||
state.pickerVisible = state.picker.state.visible = true
|
state.pickerVisible = state.picker.state.visible = true
|
||||||
state.picker.state.value = state.parsedValue
|
state.picker.state.value = state.parsedValue
|
||||||
state.picker.resetView && state.picker.resetView()
|
state.picker.resetView && state.picker.resetView()
|
||||||
// 使用nextTick方法解决time-picker组件的demo"下拉框类名"点击input,时间选择框弹出位置错误的问题,
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
updatePopper(state.picker.$el)
|
updatePopper(state.picker.$el)
|
||||||
state.picker.adjustSpinners && state.picker.adjustSpinners()
|
state.picker.adjustSpinners && state.picker.adjustSpinners()
|
||||||
|
@ -791,6 +994,7 @@ export const handlePick =
|
||||||
({ state, api }) =>
|
({ state, api }) =>
|
||||||
(date = '', visible = false) => {
|
(date = '', visible = false) => {
|
||||||
if (!state.picker) return
|
if (!state.picker) return
|
||||||
|
|
||||||
state.userInput = null
|
state.userInput = null
|
||||||
state.pickerVisible = state.picker.state.visible = visible
|
state.pickerVisible = state.picker.state.visible = visible
|
||||||
|
|
||||||
|
@ -806,25 +1010,24 @@ export const handleSelectRange = (state) => (start, end, pos) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const adjust = (value, start, end) => {
|
const adjust = (value, start, end) => {
|
||||||
if (!value) {
|
if (value) {
|
||||||
return { start, end }
|
const valueReg = /(\d+):(\d+):(\d+)(\s+.+)?/
|
||||||
}
|
|
||||||
const valueReg = /(\d+):(\d+):(\d+)(\s+.+)?/
|
|
||||||
|
|
||||||
if (valueReg.test(value)) {
|
if (valueReg.test(value)) {
|
||||||
const matched = valueReg.exec(value)
|
const matched = valueReg.exec(value)
|
||||||
const hourLength = matched[1].length
|
const hourLength = matched[1].length
|
||||||
const minuteLength = matched[2].length
|
const minuteLength = matched[2].length
|
||||||
const secondLength = matched[3].length
|
const secondLength = matched[3].length
|
||||||
|
|
||||||
if (start === 0) {
|
if (start === 0) {
|
||||||
end = hourLength
|
end = hourLength
|
||||||
} else if (start === 3) {
|
} else if (start === 3) {
|
||||||
start = hourLength + 1
|
start = hourLength + 1
|
||||||
end = hourLength + minuteLength + 1
|
end = hourLength + minuteLength + 1
|
||||||
} else {
|
} else {
|
||||||
start = hourLength + minuteLength + 2
|
start = hourLength + minuteLength + 2
|
||||||
end = hourLength + minuteLength + secondLength + 2
|
end = hourLength + minuteLength + secondLength + 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,7 +1168,6 @@ export const emitInput =
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatted = api.formatToValue(value) || val
|
const formatted = api.formatToValue(value) || val
|
||||||
|
|
||||||
if (!valueEquals(props.modelValue, formatted)) {
|
if (!valueEquals(props.modelValue, formatted)) {
|
||||||
emit('update:modelValue', formatted)
|
emit('update:modelValue', formatted)
|
||||||
}
|
}
|
||||||
|
@ -1051,19 +1253,23 @@ export const computedFormat =
|
||||||
|
|
||||||
export const computedTriggerClass =
|
export const computedTriggerClass =
|
||||||
({ props, state }) =>
|
({ props, state }) =>
|
||||||
() =>
|
() => {
|
||||||
props.suffixIcon ||
|
return (
|
||||||
props.prefixIcon ||
|
props.suffixIcon ||
|
||||||
(state.type.includes(DATEPICKER.Time) ? DATEPICKER.IconTime : DATEPICKER.IconDate)
|
props.prefixIcon ||
|
||||||
|
(state.type.includes(DATEPICKER.Time) ? DATEPICKER.IconTime : DATEPICKER.IconDate)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export const computedHaveTrigger =
|
export const computedHaveTrigger =
|
||||||
({ props }) =>
|
({ props }) =>
|
||||||
() =>
|
() => {
|
||||||
typeof props.showTrigger !== 'undefined' ? props.showTrigger : DATEPICKER.TriggerTypes.includes(props.type)
|
return typeof props.showTrigger !== 'undefined' ? props.showTrigger : DATEPICKER.TriggerTypes.includes(props.type)
|
||||||
|
}
|
||||||
|
|
||||||
export const initPopper = ({ props, hooks, vnode }) => {
|
export const initPopper = ({ props, hooks, vnode }) => {
|
||||||
const { reactive, watch, toRefs, onBeforeUnmount, onDeactivated } = hooks
|
const { reactive, watch, toRefs, onBeforeUnmount, onDeactivated } = hooks
|
||||||
// vnode就是第3参,名字有误导性
|
// tiny提示: vnode就是第3参,名字有误导性
|
||||||
const { emit, vm, slots, nextTick } = vnode
|
const { emit, vm, slots, nextTick } = vnode
|
||||||
const placementMap = DATEPICKER.PlacementMap
|
const placementMap = DATEPICKER.PlacementMap
|
||||||
|
|
||||||
|
@ -1073,7 +1279,7 @@ export const initPopper = ({ props, hooks, vnode }) => {
|
||||||
emit,
|
emit,
|
||||||
props: {
|
props: {
|
||||||
...props,
|
...props,
|
||||||
popperOptions: { boundariesPadding: 0, gpuAcceleration: false },
|
popperOptions: Object.assign({ boundariesPadding: 0, gpuAcceleration: false }, props.popperOptions),
|
||||||
visibleArrow: true,
|
visibleArrow: true,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
boundariesPadding: 5,
|
boundariesPadding: 5,
|
||||||
|
@ -1163,203 +1369,3 @@ export const setInputPaddingLeft =
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSelectionStart = ({ value, format, regx, event }) => {
|
|
||||||
const formatMatchArr = format.match(regx)
|
|
||||||
let selectionStart = getSelectionStartIndex(event)
|
|
||||||
let I = 0
|
|
||||||
|
|
||||||
if (value !== '') {
|
|
||||||
const match = value.match(/[0-9]/g)
|
|
||||||
I = match === null ? 0 : match.length
|
|
||||||
|
|
||||||
for (let i = 0; i < formatMatchArr.length; i++) {
|
|
||||||
I -= Math.max(formatMatchArr[i].length, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
I = I >= 0 ? 1 : 0
|
|
||||||
I === 1 && selectionStart >= value.length && (selectionStart = value.length - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { selectionStart, I }
|
|
||||||
}
|
|
||||||
|
|
||||||
const getNum = (value, format, regx) => {
|
|
||||||
let len = value.length
|
|
||||||
if (format && regx) {
|
|
||||||
const formatMatchArr = format.match(regx)
|
|
||||||
len = Math.max(len, formatMatchArr.join('').length)
|
|
||||||
}
|
|
||||||
let num = { str: '', arr: [] }
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
let char = value.charAt(i) ? value.charAt(i) : '00'
|
|
||||||
|
|
||||||
if (/[0-9]/.test(char)) {
|
|
||||||
num.str += char
|
|
||||||
} else {
|
|
||||||
num.arr[i] = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSelectionStartIndex = (event) => {
|
|
||||||
const inputElem = event.target
|
|
||||||
return inputElem.selectionStart - (event.data ? event.data.length : 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getNumAndSelectionStart = ({ value, format, regx, event, needSelectionStart }) => {
|
|
||||||
if (needSelectionStart) {
|
|
||||||
let { selectionStart, I } = getSelectionStart({ value, format, regx, event })
|
|
||||||
let valueStr
|
|
||||||
|
|
||||||
if (event.data) {
|
|
||||||
valueStr = value.substring(0, selectionStart) + event.data + value.substring(selectionStart + I)
|
|
||||||
selectionStart++
|
|
||||||
} else {
|
|
||||||
valueStr = value
|
|
||||||
}
|
|
||||||
|
|
||||||
const numStr = getNum(valueStr)
|
|
||||||
|
|
||||||
return { numStr, selectionStart }
|
|
||||||
} else {
|
|
||||||
const numStr = getNum(value, format, regx)
|
|
||||||
return { numStr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkFormat = ({ value, format, startIndex, selectionStart, regx, needSelectionStart }) => {
|
|
||||||
if (
|
|
||||||
(!needSelectionStart && regx.lastIndex === 0) ||
|
|
||||||
(needSelectionStart && regx.lastIndex === 0 && selectionStart >= startIndex)
|
|
||||||
) {
|
|
||||||
const subFormat = `(?<=${format.substring(0, startIndex)})(\\s*\\S*\\s*)+`
|
|
||||||
const pattern = new RegExp(subFormat, 'g')
|
|
||||||
|
|
||||||
const res = format.match(pattern)
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
value += res[0]
|
|
||||||
selectionStart = value.length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { value, selectionStart }
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveStart = (inputElem, moveStartIndex) => {
|
|
||||||
if (inputElem.setSelectionRange) {
|
|
||||||
inputElem.focus()
|
|
||||||
setTimeout(() => {
|
|
||||||
inputElem.setSelectionRange(moveStartIndex, moveStartIndex)
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 这个是 input 组件的 input 事件,应该只有一个 event 参数,input 组件的具体值从 event.target.value 中获取。
|
|
||||||
export const handleInput =
|
|
||||||
({ state, props, api }) =>
|
|
||||||
(val, event) => {
|
|
||||||
// 兼容tiny-input传参不同导致的报错问题
|
|
||||||
event = val.target ? val : event
|
|
||||||
if (props.autoFormat) {
|
|
||||||
const value = api.formatInputValue({ event, prevValue: state.displayValue })
|
|
||||||
state.userInput = value
|
|
||||||
} else {
|
|
||||||
const val = event.target.value
|
|
||||||
state.userInput = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatInputValue =
|
|
||||||
({ props, state }) =>
|
|
||||||
({ event, prevValue = '' }) => {
|
|
||||||
const val = event.target.value
|
|
||||||
const inputData = event.data
|
|
||||||
const format = state.type === 'time-select' ? 'HH:mm' : props.format || DATEPICKER.DateFormats[state.type]
|
|
||||||
if (inputData && inputData.charCodeAt() >= 48 && inputData.charCodeAt() <= 57) {
|
|
||||||
return formatText({ event, format, text: prevValue, needSelectionStart: true })
|
|
||||||
} else {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatText = ({ event, text, format, needSelectionStart = false }) => {
|
|
||||||
if (!format) return text
|
|
||||||
let cursorOffset = 0
|
|
||||||
let value = ''
|
|
||||||
let regx = /yyyy|yyy|yy|y|MM|M|dd|d|HH|hh|H|h|mm|m|ss|s|WW|W|w/g
|
|
||||||
let startIndex = 0
|
|
||||||
let { numStr, selectionStart } = getNumAndSelectionStart({
|
|
||||||
value: text,
|
|
||||||
format,
|
|
||||||
regx,
|
|
||||||
event,
|
|
||||||
needSelectionStart
|
|
||||||
})
|
|
||||||
|
|
||||||
let matchResult = regx.exec(format)
|
|
||||||
while (numStr.str !== '' && matchResult !== null) {
|
|
||||||
let subStr
|
|
||||||
let newNum
|
|
||||||
let subLen
|
|
||||||
const endIndex = matchResult.index
|
|
||||||
if (startIndex >= 0) {
|
|
||||||
value += format.substring(startIndex, endIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
selectionStart >= startIndex + cursorOffset &&
|
|
||||||
selectionStart <= endIndex + cursorOffset &&
|
|
||||||
(selectionStart = selectionStart + endIndex - startIndex)
|
|
||||||
|
|
||||||
startIndex = regx.lastIndex
|
|
||||||
subLen = startIndex - endIndex
|
|
||||||
|
|
||||||
subStr = numStr.str.substring(0, subLen)
|
|
||||||
|
|
||||||
const firstMatchChar = matchResult[0].charAt(0)
|
|
||||||
const firstChar = parseInt(subStr.charAt(0), 10)
|
|
||||||
|
|
||||||
if (numStr.str.length > 1) {
|
|
||||||
const secondChar = numStr.str.charAt(1)
|
|
||||||
newNum = 10 * firstChar + parseInt(secondChar, 10)
|
|
||||||
} else {
|
|
||||||
newNum = firstChar
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
numStr.arr[endIndex + 1] ||
|
|
||||||
(firstMatchChar === 'M' && newNum > 12) ||
|
|
||||||
(firstMatchChar === 'd' && newNum > 31) ||
|
|
||||||
(['H', 'h'].includes(firstMatchChar) && newNum > 23) ||
|
|
||||||
('ms'.includes(firstMatchChar) && newNum > 59)
|
|
||||||
) {
|
|
||||||
subStr = matchResult[0].length === 2 ? '0' + firstChar : firstChar
|
|
||||||
selectionStart++
|
|
||||||
} else {
|
|
||||||
if (subLen === 1) {
|
|
||||||
subStr = String(newNum)
|
|
||||||
subLen++
|
|
||||||
cursorOffset++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value += subStr
|
|
||||||
numStr.str = numStr.str.substring(subLen)
|
|
||||||
matchResult = regx.exec(format)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { value: val, selectionStart: cursorPos } = checkFormat({
|
|
||||||
value,
|
|
||||||
format,
|
|
||||||
startIndex,
|
|
||||||
selectionStart,
|
|
||||||
regx,
|
|
||||||
needSelectionStart
|
|
||||||
})
|
|
||||||
value = val
|
|
||||||
selectionStart = cursorPos
|
|
||||||
|
|
||||||
needSelectionStart && moveStart(event.target, selectionStart)
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
watchIsRange,
|
watchIsRange,
|
||||||
parseAsFormatAndType,
|
parseAsFormatAndType,
|
||||||
watchPickerVisible,
|
watchPickerVisible,
|
||||||
|
watchMobileVisible,
|
||||||
getValueEmpty,
|
getValueEmpty,
|
||||||
getMode,
|
getMode,
|
||||||
displayValue,
|
displayValue,
|
||||||
|
@ -177,7 +178,7 @@ const initState = ({ api, reactive, vm, computed, props, utils, parent, breakpoi
|
||||||
const initApi = ({ api, props, hooks, state, vnode, others, utils, parent }) => {
|
const initApi = ({ api, props, hooks, state, vnode, others, utils, parent }) => {
|
||||||
const { t, emit, dispatch, nextTick, vm } = vnode
|
const { t, emit, dispatch, nextTick, vm } = vnode
|
||||||
const { TimePanel, TimeRangePanel } = others
|
const { TimePanel, TimeRangePanel } = others
|
||||||
const { destroyPopper, popperElm, updatePopper, doDestroy } = initPopper({ props, hooks, vnode })
|
const { destroyPopper, popperElm, updatePopper } = initPopper({ props, hooks, vnode })
|
||||||
|
|
||||||
state.popperElm = popperElm
|
state.popperElm = popperElm
|
||||||
state.picker = null
|
state.picker = null
|
||||||
|
@ -185,7 +186,7 @@ const initApi = ({ api, props, hooks, state, vnode, others, utils, parent }) =>
|
||||||
Object.assign(api, {
|
Object.assign(api, {
|
||||||
destroyPopper,
|
destroyPopper,
|
||||||
emitDbTime: emitDbTime({ emit, state, t }),
|
emitDbTime: emitDbTime({ emit, state, t }),
|
||||||
hidePicker: hidePicker({ state, doDestroy }),
|
hidePicker: hidePicker({ destroyPopper, state }),
|
||||||
handleSelectChange: ({ tz, date }) => !state.ranged && emit('select-change', { tz, date }),
|
handleSelectChange: ({ tz, date }) => !state.ranged && emit('select-change', { tz, date }),
|
||||||
getPanel: getPanel(others),
|
getPanel: getPanel(others),
|
||||||
handleFocus: handleFocus({ emit, vm, state, api }),
|
handleFocus: handleFocus({ emit, vm, state, api }),
|
||||||
|
@ -211,7 +212,8 @@ const initApi = ({ api, props, hooks, state, vnode, others, utils, parent }) =>
|
||||||
handleClose: handleClose({ api, props, state }),
|
handleClose: handleClose({ api, props, state }),
|
||||||
displayValue: displayValue({ api, props, state }),
|
displayValue: displayValue({ api, props, state }),
|
||||||
handlePick: handlePick({ api, state }),
|
handlePick: handlePick({ api, state }),
|
||||||
watchPickerVisible: watchPickerVisible({ api, vm, dispatch, emit, props, state }),
|
watchPickerVisible: watchPickerVisible({ api, vm, dispatch, emit, props, state, nextTick }),
|
||||||
|
watchMobileVisible: watchMobileVisible({ api, props, state }),
|
||||||
formatToString: formatToString({ api, state }),
|
formatToString: formatToString({ api, state }),
|
||||||
watchIsRange: watchIsRange({ api, state, TimePanel, TimeRangePanel }),
|
watchIsRange: watchIsRange({ api, state, TimePanel, TimeRangePanel }),
|
||||||
mountPicker: mountPicker({ api, vm, props, state, updatePopper }),
|
mountPicker: mountPicker({ api, vm, props, state, updatePopper }),
|
||||||
|
@ -226,6 +228,7 @@ const initApi = ({ api, props, hooks, state, vnode, others, utils, parent }) =>
|
||||||
initApi2({ api, props, state, t, parent })
|
initApi2({ api, props, state, t, parent })
|
||||||
initMobileApi({ api, props, state, t, parent })
|
initMobileApi({ api, props, state, t, parent })
|
||||||
}
|
}
|
||||||
|
|
||||||
const initApi2 = ({ api, props, state, t, parent }) => {
|
const initApi2 = ({ api, props, state, t, parent }) => {
|
||||||
Object.assign(api, {
|
Object.assign(api, {
|
||||||
t,
|
t,
|
||||||
|
@ -268,6 +271,8 @@ const initWatch = ({ api, state, props, watch, markRaw }) => {
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(() => [state.dateMobileOption.visible, state.timeMobileOption.visible], api.watchMobileVisible)
|
||||||
|
|
||||||
watch(() => state.pickerVisible, api.watchPickerVisible)
|
watch(() => state.pickerVisible, api.watchPickerVisible)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
|
@ -813,7 +813,7 @@ export const doSuggesst =
|
||||||
api.sourceGridSelectChange({ checked: false, row, confirm: false })
|
api.sourceGridSelectChange({ checked: false, row, confirm: false })
|
||||||
})
|
})
|
||||||
|
|
||||||
if (addtions.length) {
|
if (!state.suggestList.length || addtions.length) {
|
||||||
doQuery(query)
|
doQuery(query)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -829,7 +829,7 @@ export const closeSuggestPanel =
|
||||||
const popper = vm.$refs.popper
|
const popper = vm.$refs.popper
|
||||||
let keep = !event
|
let keep = !event
|
||||||
|
|
||||||
if (event.target) {
|
if (event.target && reference) {
|
||||||
keep = reference.$el.contains(event.target) || popper.contains(event.target)
|
keep = reference.$el.contains(event.target) || popper.contains(event.target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,38 +494,14 @@ export const getPluginOption =
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
// tiny 修改: aui的 toggleCheckAll 在designConfig, 同步时要更新
|
|
||||||
export const toggleCheckAll =
|
export const toggleCheckAll =
|
||||||
({ api, state, props }) =>
|
({ api, state, props }) =>
|
||||||
(filtered) => {
|
(filtered) => {
|
||||||
// tiny 移入内部
|
let value = []
|
||||||
const getEnabledValues = (options) => {
|
// 1. 需要控制勾选或去勾选的项
|
||||||
let values = []
|
const enabledValues = state.options
|
||||||
|
.filter((op) => !op.state.disabled && !op.state.groupDisabled && !op.required && op.state.visible)
|
||||||
// tiny 新增 避免全不选时,将disabled的项目勾掉
|
.map((op) => op.value)
|
||||||
for (let i = 0; i < options.length; i++) {
|
|
||||||
const isEnabled = !options[i].state.disabled && !options[i].state.groupDisabled
|
|
||||||
const isRequired = options[i].required
|
|
||||||
const isDisabledAndChecked = !isEnabled && options[i].state.selectCls === 'checked-sur'
|
|
||||||
|
|
||||||
if (state.isSelectAll) {
|
|
||||||
// 取消选中全部,必填和禁用且选中项不可取消
|
|
||||||
if (isRequired || isDisabledAndChecked) {
|
|
||||||
values.push(options[i].value)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 选中全部,非禁用项 和 必填项和 禁用且选中项 需选中
|
|
||||||
if (isEnabled || isRequired || isDisabledAndChecked) {
|
|
||||||
values.push(options[i].value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
let value
|
|
||||||
const enabledValues = getEnabledValues(state.options)
|
|
||||||
|
|
||||||
if (filtered) {
|
if (filtered) {
|
||||||
if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') {
|
if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') {
|
||||||
|
@ -541,10 +517,18 @@ export const toggleCheckAll =
|
||||||
|
|
||||||
unchecked.length ? (value = enabledValues) : (value = [])
|
unchecked.length ? (value = enabledValues) : (value = [])
|
||||||
} else if (state.selectCls === 'checked-sur') {
|
} else if (state.selectCls === 'checked-sur') {
|
||||||
// tiny 新增
|
value = []
|
||||||
value = getEnabledValues(state.options)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 2. 必选项
|
||||||
|
const requiredValue = state.options.filter((op) => op.required).map((op) => op.value)
|
||||||
|
|
||||||
|
// 3. 禁用且已设置为勾选的项
|
||||||
|
const disabledSelectedValues = state.options
|
||||||
|
.filter((op) => (op.state.disabled || op.state.groupDisabled) && op.state.selectCls === 'checked-sur')
|
||||||
|
.map((op) => op.value)
|
||||||
|
|
||||||
|
value = [...value, ...requiredValue, ...disabledSelectedValues]
|
||||||
|
|
||||||
api.setSoftFocus()
|
api.setSoftFocus()
|
||||||
|
|
||||||
|
@ -1278,10 +1262,9 @@ export const watchValue =
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.filterable && !props.reserveKeyword) {
|
if (props.filterable && !props.reserveKeyword) {
|
||||||
const isChange = false
|
// tiny 优化: 多选且props.reserveKeyword为false时, aui此处会多请求一次
|
||||||
const isInput = true
|
// searchable时,不清空query, 这样才能保持搜索结果
|
||||||
props.renderType !== constants.TYPE.Grid && (state.query = '')
|
props.renderType !== constants.TYPE.Grid && !props.searchable && (state.query = '')
|
||||||
api.handleQueryChange(state.query, isChange, isInput)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1549,7 +1532,7 @@ export const queryVisibleOptions =
|
||||||
if (props.optimization) {
|
if (props.optimization) {
|
||||||
return optmzApis.queryVisibleOptions(vm, isMobileFirstMode)
|
return optmzApis.queryVisibleOptions(vm, isMobileFirstMode)
|
||||||
} else {
|
} else {
|
||||||
return Array.from(vm.$refs.scrollbar.$el.querySelectorAll('[data-index]:not([style*="display: none"])'))
|
return Array.from(vm.$refs.scrollbar?.$el.querySelectorAll('[data-index]:not([style*="display: none"])') || [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1839,11 +1822,16 @@ export const watchHoverIndex =
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleDropdownClick =
|
export const handleDropdownClick =
|
||||||
({ emit }) =>
|
({ vm, state, props, emit }) =>
|
||||||
($event) => {
|
($event) => {
|
||||||
|
if (props.allowCopy && vm.$refs.reference) {
|
||||||
|
vm.$refs.reference.$el.querySelector('input').selectionEnd = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
state.softFocus = false
|
||||||
|
|
||||||
emit('dropdown-click', $event)
|
emit('dropdown-click', $event)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleEnterTag =
|
export const handleEnterTag =
|
||||||
({ state }) =>
|
({ state }) =>
|
||||||
($event, key) => {
|
($event, key) => {
|
||||||
|
|
|
@ -169,7 +169,7 @@ export const api = [
|
||||||
'clearSearchText'
|
'clearSearchText'
|
||||||
]
|
]
|
||||||
|
|
||||||
const initState = ({ reactive, computed, props, api, emitter, parent, constants, useBreakpoint, vm }) => {
|
const initState = ({ reactive, computed, props, api, emitter, parent, constants, useBreakpoint, vm, designConfig }) => {
|
||||||
const stateAdd = initStateAdd({ computed, props, api, parent })
|
const stateAdd = initStateAdd({ computed, props, api, parent })
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
...stateAdd,
|
...stateAdd,
|
||||||
|
@ -226,7 +226,13 @@ const initState = ({ reactive, computed, props, api, emitter, parent, constants,
|
||||||
// tiny 新增
|
// tiny 新增
|
||||||
getIcon: computed(() => api.computedGetIcon()),
|
getIcon: computed(() => api.computedGetIcon()),
|
||||||
getTagType: computed(() => api.computedGetTagType()),
|
getTagType: computed(() => api.computedGetTagType()),
|
||||||
isSelectAll: computed(() => state.selectCls === 'checked-sur')
|
isSelectAll: computed(() => state.selectCls === 'checked-sur'),
|
||||||
|
autoHideDownIcon: (() => {
|
||||||
|
if (designConfig?.state && 'autoHideDownIcon' in designConfig.state) {
|
||||||
|
return designConfig.state.autoHideDownIcon
|
||||||
|
}
|
||||||
|
return true // tiny 默认为true
|
||||||
|
})()
|
||||||
})
|
})
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
@ -431,7 +437,7 @@ const addApi = ({
|
||||||
mounted: mounted({ api, parent, state, props, vm, designConfig }),
|
mounted: mounted({ api, parent, state, props, vm, designConfig }),
|
||||||
unMount: unMount({ api, parent, vm, state }),
|
unMount: unMount({ api, parent, vm, state }),
|
||||||
watchOptimizeOpts: watchOptimizeOpts({ props, state }),
|
watchOptimizeOpts: watchOptimizeOpts({ props, state }),
|
||||||
handleDropdownClick: handleDropdownClick({ emit }),
|
handleDropdownClick: handleDropdownClick({ props, vm, state, emit }),
|
||||||
handleEnterTag: handleEnterTag({ state }),
|
handleEnterTag: handleEnterTag({ state }),
|
||||||
calcCollapseTags: calcCollapseTags({ state, vm }),
|
calcCollapseTags: calcCollapseTags({ state, vm }),
|
||||||
initValue: initValue({ state }),
|
initValue: initValue({ state }),
|
||||||
|
@ -555,8 +561,19 @@ export const renderless = (
|
||||||
{ computed, onBeforeUnmount, onMounted, reactive, watch, provide, inject },
|
{ computed, onBeforeUnmount, onMounted, reactive, watch, provide, inject },
|
||||||
{ vm, parent, emit, constants, nextTick, dispatch, t, emitter, isMobileFirstMode, useBreakpoint, designConfig }
|
{ vm, parent, emit, constants, nextTick, dispatch, t, emitter, isMobileFirstMode, useBreakpoint, designConfig }
|
||||||
) => {
|
) => {
|
||||||
const api = {}
|
const api: any = {}
|
||||||
const state = initState({ reactive, computed, props, api, emitter, parent, constants, useBreakpoint, vm })
|
const state = initState({
|
||||||
|
reactive,
|
||||||
|
computed,
|
||||||
|
props,
|
||||||
|
api,
|
||||||
|
emitter,
|
||||||
|
parent,
|
||||||
|
constants,
|
||||||
|
useBreakpoint,
|
||||||
|
vm,
|
||||||
|
designConfig
|
||||||
|
})
|
||||||
const dialog = inject('dialog', null)
|
const dialog = inject('dialog', null)
|
||||||
|
|
||||||
provide('selectEmitter', state.selectEmitter)
|
provide('selectEmitter', state.selectEmitter)
|
||||||
|
@ -579,9 +596,7 @@ export const renderless = (
|
||||||
isMobileFirstMode,
|
isMobileFirstMode,
|
||||||
designConfig
|
designConfig
|
||||||
})
|
})
|
||||||
initWatch({ watch, props, api, state, nextTick })
|
|
||||||
onMounted(api.mounted)
|
|
||||||
onBeforeUnmount(api.unMount)
|
|
||||||
parent.$on('handle-clear', (event) => {
|
parent.$on('handle-clear', (event) => {
|
||||||
api.handleClearClick(event)
|
api.handleClearClick(event)
|
||||||
})
|
})
|
||||||
|
@ -599,5 +614,14 @@ export const renderless = (
|
||||||
state.selectEmitter.on(constants.EVENT_NAME.setSelected, api.setSelected)
|
state.selectEmitter.on(constants.EVENT_NAME.setSelected, api.setSelected)
|
||||||
state.selectEmitter.on(constants.EVENT_NAME.initValue, api.initValue)
|
state.selectEmitter.on(constants.EVENT_NAME.initValue, api.initValue)
|
||||||
|
|
||||||
|
initWatch({ watch, props, api, state, nextTick })
|
||||||
|
|
||||||
|
onMounted(api.mounted)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
api.unMount()
|
||||||
|
dialog && dialog.state.emitter.off('handleSelectClose', api.handleClose)
|
||||||
|
})
|
||||||
|
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,6 +349,7 @@ export const addNode =
|
||||||
state.tree.state.emitter.emit('tree-node-add', event, node)
|
state.tree.state.emitter.emit('tree-node-add', event, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tiny 新增
|
||||||
export const computedExpandIcon =
|
export const computedExpandIcon =
|
||||||
({ designConfig }) =>
|
({ designConfig }) =>
|
||||||
(treeRoot, state) => {
|
(treeRoot, state) => {
|
||||||
|
@ -356,6 +357,7 @@ export const computedExpandIcon =
|
||||||
return state.tree.icon
|
return state.tree.icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tiny 新增的判断。 显示线时强制切换图标,仅smb定制了
|
||||||
if (treeRoot.showLine) {
|
if (treeRoot.showLine) {
|
||||||
const expandIcon = designConfig?.icons?.expanded || 'icon-minus-square'
|
const expandIcon = designConfig?.icons?.expanded || 'icon-minus-square'
|
||||||
const collapseIcon = designConfig?.icons?.collapse || 'icon-plus-square'
|
const collapseIcon = designConfig?.icons?.collapse || 'icon-plus-square'
|
||||||
|
@ -364,7 +366,7 @@ export const computedExpandIcon =
|
||||||
|
|
||||||
return 'icon-chevron-right'
|
return 'icon-chevron-right'
|
||||||
}
|
}
|
||||||
|
// tiny 新增
|
||||||
export const computedIndent =
|
export const computedIndent =
|
||||||
() =>
|
() =>
|
||||||
({ node, showLine }, { tree }) => {
|
({ node, showLine }, { tree }) => {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import {
|
||||||
deleteNode,
|
deleteNode,
|
||||||
onSiblingToggleExpand,
|
onSiblingToggleExpand,
|
||||||
watchExpandedChange,
|
watchExpandedChange,
|
||||||
|
// tiny 新增
|
||||||
computedExpandIcon,
|
computedExpandIcon,
|
||||||
computedIndent
|
computedIndent
|
||||||
} from './index'
|
} from './index'
|
||||||
|
|
|
@ -250,7 +250,7 @@ export const updateOptions =
|
||||||
export const autoSelect =
|
export const autoSelect =
|
||||||
({ props, state, nextTick }) =>
|
({ props, state, nextTick }) =>
|
||||||
(usersList) => {
|
(usersList) => {
|
||||||
if (!usersList.length) {
|
if (!usersList.length || (props.multiple && props.multipleLimit && state.user.length >= props.multipleLimit)) {
|
||||||
return nextTick()
|
return nextTick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,11 +138,15 @@
|
||||||
@apply text-base;
|
@apply text-base;
|
||||||
@apply items-center;
|
@apply items-center;
|
||||||
|
|
||||||
.@{drawer-prefix-cls}__title {
|
.@{drawer-prefix-cls}__header-left {
|
||||||
@apply ~'max-w-[80%]';
|
@apply ~'max-w-[80%]';
|
||||||
@apply pr-4;
|
|
||||||
@apply text-left;
|
// 标题增加帮助提示, 勿覆盖
|
||||||
@apply truncate;
|
.@{drawer-prefix-cls}__title {
|
||||||
|
@apply pr-4;
|
||||||
|
@apply text-left;
|
||||||
|
@apply truncate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{drawer-prefix-cls}__header-right {
|
.@{drawer-prefix-cls}__header-right {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"themeName": "华为SaaS设计系统主题",
|
"themeName": "SaaS设计系统主题",
|
||||||
"themeColor": [
|
"themeColor": [
|
||||||
{
|
{
|
||||||
"mode": "light",
|
"mode": "light",
|
||||||
|
|
|
@ -150,7 +150,6 @@
|
||||||
border-bottom: 1px solid var(--ti-drawer-divider-border-color);
|
border-bottom: 1px solid var(--ti-drawer-divider-border-color);
|
||||||
|
|
||||||
.@{drawer-prefix-cls}__title {
|
.@{drawer-prefix-cls}__title {
|
||||||
max-width: 80%;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -161,7 +160,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{drawer-prefix-cls}__header-left {
|
.@{drawer-prefix-cls}__header-left {
|
||||||
flex: 1;
|
max-width: 80%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-right: 16px;
|
padding-right: 16px;
|
||||||
|
|
|
@ -425,6 +425,10 @@
|
||||||
transform: rotate(0);
|
transform: rotate(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-leaf {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
:tabindex="tabindex"
|
:tabindex="tabindex"
|
||||||
v-bind="a($attrs, ['class', 'style'], true)"
|
v-bind="a($attrs, ['class', 'style', 'id'], true)"
|
||||||
>
|
>
|
||||||
<icon-loading v-if="loading" :class="gcls('loading-svg')" />
|
<icon-loading v-if="loading" :class="gcls('loading-svg')" />
|
||||||
<component
|
<component
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
:tabindex="tabindex"
|
:tabindex="tabindex"
|
||||||
v-bind="a($attrs, ['class', 'style'], true)"
|
v-bind="a($attrs, ['class', 'style', 'title', 'id'], true)"
|
||||||
>
|
>
|
||||||
<icon-loading v-if="loading" class="tiny-icon-loading tiny-svg-size" />
|
<icon-loading v-if="loading" class="tiny-icon-loading tiny-svg-size" />
|
||||||
<component v-if="icon && !loading" :is="icon" :class="{ 'is-text': text || slots.default }" />
|
<component v-if="icon && !loading" :is="icon" :class="{ 'is-text': text || slots.default }" />
|
||||||
|
|
|
@ -100,7 +100,8 @@ import type { ICheckboxApi } from '@opentiny/vue-renderless/types/checkbox.type'
|
||||||
import Tooltip from '@opentiny/vue-tooltip'
|
import Tooltip from '@opentiny/vue-tooltip'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['update:modelValue', 'change', 'complete', 'click'],
|
// tiny 新增。 renderless中,没有emit('click')的地方。 此处勿声明,否则会造成丢失click事件。
|
||||||
|
emits: ['update:modelValue', 'change', 'complete'],
|
||||||
props: [
|
props: [
|
||||||
...props,
|
...props,
|
||||||
'modelValue',
|
'modelValue',
|
||||||
|
|
|
@ -773,7 +773,7 @@ export const Cell = {
|
||||||
renderEditHeader(h, params) {
|
renderEditHeader(h, params) {
|
||||||
let { $table, column } = params
|
let { $table, column } = params
|
||||||
let { editConfig, editRules, validOpts } = $table
|
let { editConfig, editRules, validOpts } = $table
|
||||||
let { filter, remoteSort, sortable, type } = column
|
let { filter, remoteSort, sortable, type, own } = column
|
||||||
let icon = GLOBAL_CONFIG.icon
|
let icon = GLOBAL_CONFIG.icon
|
||||||
let isRequired
|
let isRequired
|
||||||
|
|
||||||
|
@ -799,7 +799,7 @@ export const Cell = {
|
||||||
|
|
||||||
let vNodes = [
|
let vNodes = [
|
||||||
isRequired && showAsterisk ? h('i', { class: `tiny-icon ${icon.required}` }) : null,
|
isRequired && showAsterisk ? h('i', { class: `tiny-icon ${icon.required}` }) : null,
|
||||||
!editConfig || !column.showIcon ? null : h(icon.edit, { class: 'tiny-grid-edit-icon tiny-svg-size' })
|
!editConfig || !own.showIcon ? null : h(icon.edit, { class: 'tiny-grid-edit-icon tiny-svg-size' })
|
||||||
]
|
]
|
||||||
|
|
||||||
vNodes = vNodes.concat(Cell.renderHeader(h, params))
|
vNodes = vNodes.concat(Cell.renderHeader(h, params))
|
||||||
|
|
|
@ -57,7 +57,7 @@ export const createHandlerOnEnd = ({ _vm, refresh }) => {
|
||||||
if (insertRecords.length) {
|
if (insertRecords.length) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const options = { children: 'children' }
|
const options = { children: (_vm.treeConfig || {}).children || 'children' }
|
||||||
const targetTrElem = event.item
|
const targetTrElem = event.item
|
||||||
const { parentNode: wrapperElem, previousElementSibling: prevTrElem } = targetTrElem
|
const { parentNode: wrapperElem, previousElementSibling: prevTrElem } = targetTrElem
|
||||||
// 这里优先使用用户通过props传递过来的表格数据,所以拖拽后会改变原始数据
|
// 这里优先使用用户通过props传递过来的表格数据,所以拖拽后会改变原始数据
|
||||||
|
|
|
@ -176,6 +176,7 @@ export default {
|
||||||
name: `${$prefix}GridFooter`,
|
name: `${$prefix}GridFooter`,
|
||||||
props: {
|
props: {
|
||||||
fixedColumn: Array,
|
fixedColumn: Array,
|
||||||
|
fixedType: String,
|
||||||
footerData: Array,
|
footerData: Array,
|
||||||
size: String,
|
size: String,
|
||||||
tableColumn: Array,
|
tableColumn: Array,
|
||||||
|
@ -193,7 +194,7 @@ export default {
|
||||||
elemStore[`${keyPrefix}x-space`] = $refs.xSpace
|
elemStore[`${keyPrefix}x-space`] = $refs.xSpace
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
let { $parent: $table, buildParamFunc, footerData, tableColumn } = this
|
let { $parent: $table, buildParamFunc, fixedColumn, fixedType, footerData, tableColumn } = this
|
||||||
let {
|
let {
|
||||||
align: allAlign,
|
align: allAlign,
|
||||||
columnKey,
|
columnKey,
|
||||||
|
@ -203,7 +204,7 @@ export default {
|
||||||
footerSpanMethod,
|
footerSpanMethod,
|
||||||
columnStore
|
columnStore
|
||||||
} = $table
|
} = $table
|
||||||
let { overflowX, showOverflow: allColumnOverflow, tableLayout, tableListeners } = $table
|
let { overflowX, showOverflow: allColumnOverflow, tableLayout, tableListeners, renderFooter } = $table
|
||||||
|
|
||||||
let tableAttrs = { cellspacing: 0, cellpadding: 0, border: 0 }
|
let tableAttrs = { cellspacing: 0, cellpadding: 0, border: 0 }
|
||||||
let colgroupVNode = renderColgroup(tableColumn)
|
let colgroupVNode = renderColgroup(tableColumn)
|
||||||
|
@ -219,6 +220,8 @@ export default {
|
||||||
}
|
}
|
||||||
let tfootVNode = renderTfoot(Object.assign(arg1, arg2))
|
let tfootVNode = renderTfoot(Object.assign(arg1, arg2))
|
||||||
|
|
||||||
|
const renderParams = { $table, columns: tableColumn, footerData, fixedColumns: fixedColumn, fixedType }
|
||||||
|
|
||||||
return h(
|
return h(
|
||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
|
@ -227,21 +230,23 @@ export default {
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
h('div', { class: 'tiny-grid-body__x-space', ref: 'xSpace' }),
|
h('div', { class: 'tiny-grid-body__x-space', ref: 'xSpace' }),
|
||||||
h(
|
typeof renderFooter === 'function'
|
||||||
'table',
|
? renderFooter(renderParams, h)
|
||||||
{
|
: h(
|
||||||
class: 'tiny-grid__footer',
|
'table',
|
||||||
style: { tableLayout },
|
{
|
||||||
attrs: tableAttrs,
|
class: 'tiny-grid__footer',
|
||||||
ref: 'table'
|
style: { tableLayout },
|
||||||
},
|
attrs: tableAttrs,
|
||||||
[
|
ref: 'table'
|
||||||
// 列宽
|
},
|
||||||
colgroupVNode,
|
[
|
||||||
// 底部
|
// 列宽
|
||||||
tfootVNode
|
colgroupVNode,
|
||||||
]
|
// 底部
|
||||||
)
|
tfootVNode
|
||||||
|
]
|
||||||
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,7 +33,9 @@ export default {
|
||||||
this.recalculate()
|
this.recalculate()
|
||||||
}, GlobalConfig.resizeInterval)
|
}, GlobalConfig.resizeInterval)
|
||||||
|
|
||||||
resizeObserver.observe(this.getParentElem())
|
const parentElem = this.getParentElem()
|
||||||
|
|
||||||
|
parentElem && resizeObserver.observe(parentElem)
|
||||||
this.$resize = resizeObserver
|
this.$resize = resizeObserver
|
||||||
},
|
},
|
||||||
unbindResize() {
|
unbindResize() {
|
||||||
|
|
|
@ -141,7 +141,7 @@ const setTotalRows = (_vm) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTotalRows = (_vm) => {
|
const getTotalRows = (_vm) => {
|
||||||
const { afterFullData, scrollYLoad, treeConfig } = _vm
|
const { afterFullData, scrollYLoad, scrollLoad, treeConfig } = _vm
|
||||||
let totalRows = afterFullData.length
|
let totalRows = afterFullData.length
|
||||||
|
|
||||||
if (scrollYLoad && treeConfig) {
|
if (scrollYLoad && treeConfig) {
|
||||||
|
@ -152,6 +152,11 @@ const getTotalRows = (_vm) => {
|
||||||
totalRows = TOTALROWS_MAP.get(_vm)
|
totalRows = TOTALROWS_MAP.get(_vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 滚动分页场景总行数由(afterFullData.length)调整为(scrollLoad.pageSize),解决最后一页数据不足时滚动条位置改变问题
|
||||||
|
if (scrollLoad) {
|
||||||
|
totalRows = scrollLoad.pageSize || 10
|
||||||
|
}
|
||||||
|
|
||||||
return totalRows
|
return totalRows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import RichText from './src/pc.vue'
|
||||||
|
import '@opentiny/vue-theme/rich-text/index.css'
|
||||||
|
|
||||||
|
RichText.model = {
|
||||||
|
prop: 'modelValue',
|
||||||
|
event: 'update:modelValue'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
RichText.install = function (Vue) {
|
||||||
|
Vue.component(RichText.name, RichText)
|
||||||
|
}
|
||||||
|
|
||||||
|
RichText.version = process.env.COMPONENT_VERSION
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (process.env.BUILD_TARGET === 'runtime') {
|
||||||
|
if (typeof window !== 'undefined' && window.Vue) {
|
||||||
|
RichText.install(window.Vue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RichText
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "@opentiny/vue-rich-text",
|
||||||
|
"version": "3.14.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "index.ts",
|
||||||
|
"sideEffects": false,
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@opentiny-internal/vue-test-utils": "workspace:*",
|
||||||
|
"vitest": "^0.31.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "pnpm -w build:ui $npm_package_name",
|
||||||
|
"//postversion": "pnpm build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@opentiny/vue-icon": "workspace:~",
|
||||||
|
"@opentiny/vue-common": "workspace:~",
|
||||||
|
"@opentiny/vue-locale": "workspace:~",
|
||||||
|
"quill": "^1.3.7"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
<template>
|
||||||
|
<div class="quill-editor" :class="{ 'is-display-only': state.isDisplayOnly }">
|
||||||
|
<slot name="toolbar"></slot>
|
||||||
|
<div ref="editor" @paste="handlePaste"></div>
|
||||||
|
<div class="toolbar-icon">
|
||||||
|
<icon-fileupload ref="iconFile"></icon-fileupload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { $prefix, setup, defineComponent } from '@opentiny/vue-common'
|
||||||
|
import Quill from 'quill'
|
||||||
|
import ImageDrop from '@opentiny/vue-renderless/rich-text/module/image-drop'
|
||||||
|
import ImageUpload from '@opentiny/vue-renderless/rich-text/module/image-upload'
|
||||||
|
import FileUpload from '@opentiny/vue-renderless/rich-text/module/file-upload'
|
||||||
|
import Modal from '@opentiny/vue-modal'
|
||||||
|
import { IconFileupload } from '@opentiny/vue-icon'
|
||||||
|
import { renderless, api } from '@opentiny/vue-renderless/rich-text/vue'
|
||||||
|
|
||||||
|
const $constants = {
|
||||||
|
MAX_LENGTH: Number.MAX_SAFE_INTEGER
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: $prefix + 'RichText',
|
||||||
|
components: {
|
||||||
|
IconFileupload: IconFileupload()
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
_constants: {
|
||||||
|
type: Object,
|
||||||
|
default: () => $constants
|
||||||
|
},
|
||||||
|
content: String,
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
fileUpload: Object,
|
||||||
|
globalOptions: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
imageDrop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
imageUpload: Object,
|
||||||
|
keepClass: [String, Array],
|
||||||
|
modelValue: String,
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
tableModule: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
displayOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, context) {
|
||||||
|
return setup({
|
||||||
|
props,
|
||||||
|
context,
|
||||||
|
renderless,
|
||||||
|
api,
|
||||||
|
mono: true,
|
||||||
|
extendOptions: {
|
||||||
|
Quill,
|
||||||
|
ImageDrop,
|
||||||
|
ImageUpload,
|
||||||
|
FileUpload,
|
||||||
|
Modal
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
|
@ -190,10 +190,10 @@
|
||||||
</template>
|
</template>
|
||||||
</tiny-tooltip>
|
</tiny-tooltip>
|
||||||
</span>
|
</span>
|
||||||
|
<!-- tiny 新增:searchable时, 这里不显示 state.query -->
|
||||||
<input
|
<input
|
||||||
ref="input"
|
ref="input"
|
||||||
v-if="filterable && !state.selectDisabled"
|
v-show="filterable && !searchable && !state.selectDisabled"
|
||||||
v-model="state.query"
|
v-model="state.query"
|
||||||
type="text"
|
type="text"
|
||||||
class="tiny-select__input"
|
class="tiny-select__input"
|
||||||
|
@ -272,10 +272,15 @@
|
||||||
@click="handleClearClick"
|
@click="handleClearClick"
|
||||||
@mouseenter="state.inputHovering = true"
|
@mouseenter="state.inputHovering = true"
|
||||||
></icon-close>
|
></icon-close>
|
||||||
<!-- tiny 新增 自定义getIcon . tiny 显示 close时, 不显示向下的箭头。 aui是同时显示2个, 待使用designConfig解决这个 -->
|
<!-- tiny 新增 自定义getIcon .
|
||||||
|
tiny 的 autoHideDownIcon=true, 显示 close时, 不显示向下的箭头。
|
||||||
|
aui是同时显示2个。 -->
|
||||||
<component
|
<component
|
||||||
v-else
|
v-show="
|
||||||
v-show="!(remote && filterable && !remoteConfig.showIcon)"
|
state.autoHideDownIcon
|
||||||
|
? !state.showClose && !(remote && filterable && !remoteConfig.showIcon)
|
||||||
|
: !(remote && filterable && !remoteConfig.showIcon)
|
||||||
|
"
|
||||||
:is="state.getIcon.icon"
|
:is="state.getIcon.icon"
|
||||||
:class="[
|
:class="[
|
||||||
'tiny-svg-size',
|
'tiny-svg-size',
|
||||||
|
@ -424,11 +429,8 @@
|
||||||
v-show="state.options.length > 0 && !loading"
|
v-show="state.options.length > 0 && !loading"
|
||||||
>
|
>
|
||||||
<slot name="dropdown"></slot>
|
<slot name="dropdown"></slot>
|
||||||
<!-- tiny 新增 : !filterable 的判断 有过滤时,不显示全部。 aui没有该判断 -->
|
|
||||||
<li
|
<li
|
||||||
v-if="
|
v-if="multiple && showCheck && showAlloption && !state.multipleLimit && !state.query && !remote"
|
||||||
multiple && showCheck && showAlloption && !state.multipleLimit && !state.query && !remote && !filterable
|
|
||||||
"
|
|
||||||
class="tiny-option tiny-select-dropdown__item"
|
class="tiny-option tiny-select-dropdown__item"
|
||||||
data-tag="tiny-select-dropdown-item"
|
data-tag="tiny-select-dropdown-item"
|
||||||
:class="[
|
:class="[
|
||||||
|
@ -443,9 +445,9 @@
|
||||||
>
|
>
|
||||||
<!-- <component :is="`icon-${state.selectCls}`" :class="['tiny-svg-size', state.selectCls]" />
|
<!-- <component :is="`icon-${state.selectCls}`" :class="['tiny-svg-size', state.selectCls]" />
|
||||||
<span>{{ t('ui.base.all') }}</span> -->
|
<span>{{ t('ui.base.all') }}</span> -->
|
||||||
<!-- tiny 新增: 使用checkbox 代替 svg -->
|
<!-- tiny 新增: 使用checkbox 代替 svg , 列表模式 -->
|
||||||
<tiny-checkbox
|
<tiny-checkbox
|
||||||
:model-value="state.isSelectAll"
|
:model-value="state.selectCls === 'checked-sur'"
|
||||||
:indeterminate="state.selectCls === 'halfselect'"
|
:indeterminate="state.selectCls === 'halfselect'"
|
||||||
:class="state.selectCls"
|
:class="state.selectCls"
|
||||||
>
|
>
|
||||||
|
@ -460,8 +462,7 @@
|
||||||
!state.multipleLimit &&
|
!state.multipleLimit &&
|
||||||
state.query &&
|
state.query &&
|
||||||
!state.emptyText &&
|
!state.emptyText &&
|
||||||
!remote &&
|
!remote
|
||||||
!filterable
|
|
||||||
"
|
"
|
||||||
class="tiny-option tiny-select-dropdown__item"
|
class="tiny-option tiny-select-dropdown__item"
|
||||||
data-tag="tiny-select-dropdown-item"
|
data-tag="tiny-select-dropdown-item"
|
||||||
|
@ -477,9 +478,9 @@
|
||||||
>
|
>
|
||||||
<!-- <component :is="`icon-${state.filteredSelectCls}`" :class="['tiny-svg-size', state.filteredSelectCls]" />
|
<!-- <component :is="`icon-${state.filteredSelectCls}`" :class="['tiny-svg-size', state.filteredSelectCls]" />
|
||||||
<span>{{ t('ui.base.all') }}</span> -->
|
<span>{{ t('ui.base.all') }}</span> -->
|
||||||
<!-- tiny 新增: 使用checkbox 代替 svg -->
|
<!-- tiny 新增: 使用checkbox 代替 svg,过滤模式 -->
|
||||||
<tiny-checkbox
|
<tiny-checkbox
|
||||||
:model-value="state.isSelectAll"
|
:model-value="state.filteredSelectCls === 'checked-sur'"
|
||||||
:indeterminate="state.filteredSelectCls === 'halfselect'"
|
:indeterminate="state.filteredSelectCls === 'halfselect'"
|
||||||
:class="state.selectCls"
|
:class="state.selectCls"
|
||||||
>
|
>
|
||||||
|
|
|
@ -70,6 +70,7 @@ export const tabsProps = {
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: $prefix + 'Tabs',
|
name: $prefix + 'Tabs',
|
||||||
|
emits: ['tab-nav-update'],
|
||||||
props: tabsProps,
|
props: tabsProps,
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
return $setup({ props, context, template })
|
return $setup({ props, context, template })
|
||||||
|
|
|
@ -67,7 +67,6 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span
|
<span
|
||||||
v-if="!node.isLeaf"
|
|
||||||
:class="['tree-node-icon', { 'is-disabled': node.disabled }]"
|
:class="['tree-node-icon', { 'is-disabled': node.disabled }]"
|
||||||
@click="handleExpandIconClick($event, node)"
|
@click="handleExpandIconClick($event, node)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -85,6 +85,10 @@ export const uploadListProps = {
|
||||||
lockScroll: {
|
lockScroll: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
compact: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
multipleLimit: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:collapse-tags="collapseTags"
|
:collapse-tags="collapseTags"
|
||||||
:multiple="multiple"
|
:multiple="multiple"
|
||||||
|
:multipleLimit="multipleLimit"
|
||||||
@change="userChange"
|
@change="userChange"
|
||||||
:loading="state.loading"
|
:loading="state.loading"
|
||||||
filterable
|
filterable
|
||||||
|
@ -123,7 +124,8 @@ export default defineComponent({
|
||||||
'maxWidth',
|
'maxWidth',
|
||||||
'keepFocus',
|
'keepFocus',
|
||||||
'changeCompat',
|
'changeCompat',
|
||||||
'multiLineDrag'
|
'multiLineDrag',
|
||||||
|
'multipleLimit'
|
||||||
],
|
],
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
return setup({ props, context, renderless, api })
|
return setup({ props, context, renderless, api })
|
||||||
|
|
Loading…
Reference in New Issue