feat(number-animation): Add NumberAnimation component (#3301)
* feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component
This commit is contained in:
parent
f98b9367d7
commit
b76c76d183
|
@ -0,0 +1,104 @@
|
||||||
|
export default {
|
||||||
|
mode: ['pc'],
|
||||||
|
apis: [
|
||||||
|
{
|
||||||
|
name: 'number-animation',
|
||||||
|
type: 'component',
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
name: 'active',
|
||||||
|
type: 'boolean',
|
||||||
|
defaultValue: 'true',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '是否开始动画',
|
||||||
|
'en-US': 'Whether or not start animation'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'basic-usage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
type: 'number',
|
||||||
|
defaultValue: '3000',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '动画持续时间',
|
||||||
|
'en-US': 'Animation duration'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'basic-usage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'from',
|
||||||
|
type: 'number',
|
||||||
|
defaultValue: '0',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '数值动画起始值',
|
||||||
|
'en-US': 'Starting value of numerical animation'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'basic-usage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'to',
|
||||||
|
type: 'number',
|
||||||
|
defaultValue: '',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '目标值',
|
||||||
|
'en-US': 'Target value'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'basic-usage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'precision',
|
||||||
|
type: 'number',
|
||||||
|
defaultValue: '0',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '精度,保留小数点后几位',
|
||||||
|
'en-US': 'Precision, rounded to a few decimal places.'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'precision'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'separator',
|
||||||
|
type: 'string',
|
||||||
|
defaultValue: ',',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '千分位分隔符',
|
||||||
|
'en-US': 'Thousandth separator'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'separator'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
name: 'finish',
|
||||||
|
type: '() => void',
|
||||||
|
defaultValue: '',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '动画结束后的回调',
|
||||||
|
'en-US': 'The callback after the animation ends.'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'finish-events'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
methods: [
|
||||||
|
{
|
||||||
|
name: 'play',
|
||||||
|
type: '() => void',
|
||||||
|
defaultValue: '',
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '播放动画',
|
||||||
|
'en-US': 'Play Animation'
|
||||||
|
},
|
||||||
|
mode: ['pc'],
|
||||||
|
pcDemo: 'finish-events'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
slots: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
const numberAnimationRef = ref(null)
|
||||||
|
const fromVal = ref(0)
|
||||||
|
const toVal = ref(12309)
|
||||||
|
function handleClick() {
|
||||||
|
numberAnimationRef.value?.play()
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('基本用法', async ({ page }) => {
|
||||||
|
page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误
|
||||||
|
await page.goto('number-animation#basic-usage') // 要测试的示例的相对地址
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
await page.locator('#basic-usage').getByText('12,039')
|
||||||
|
})
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="jsx">
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TinyButton,
|
||||||
|
TinyNumberAnimation
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fromVal: 0,
|
||||||
|
toVal: 12039
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$refs.numberAnimationRef.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" @finish="handleFinish" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { TinyButton, TinyNumberAnimation, TinyModal } from '@opentiny/vue'
|
||||||
|
|
||||||
|
const numberAnimationRef = ref(null)
|
||||||
|
const fromVal = ref(0)
|
||||||
|
const toVal = ref(900)
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
numberAnimationRef.value?.play()
|
||||||
|
}
|
||||||
|
function handleFinish() {
|
||||||
|
TinyModal.message({ message: '动画结束了', status: 'info' })
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('动画播放完成', async ({ page }) => {
|
||||||
|
page.on('pageerror', (exception) => expect(exception).toBeNull())
|
||||||
|
await page.goto('number-animation#finish-events')
|
||||||
|
await page.getByRole('button', { name: '播放' }).click()
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
await page.locator('#finish-events').getByText('900')
|
||||||
|
const messageLocator = page.locator('.tiny-modal__box').filter({ hasText: '动画结束了' })
|
||||||
|
await expect(messageLocator).toBeVisible()
|
||||||
|
})
|
|
@ -0,0 +1,29 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" @finish="handleFinish" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="jsx">
|
||||||
|
import { TinyButton, TinyNumberAnimation, TinyModal } from '@opentiny/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TinyButton,
|
||||||
|
TinyNumberAnimation
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fromVal: 0,
|
||||||
|
toVal: 900
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$refs.numberAnimationRef.play()
|
||||||
|
},
|
||||||
|
handleFinish() {
|
||||||
|
TinyModal.message({ message: '动画结束了', status: 'info' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" :precision="4" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
const numberAnimationRef = ref(null)
|
||||||
|
const fromVal = ref(0.0)
|
||||||
|
const toVal = ref(24)
|
||||||
|
function handleClick() {
|
||||||
|
numberAnimationRef.value?.play()
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('精度', async ({ page }) => {
|
||||||
|
page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误
|
||||||
|
await page.goto('number-animation#precision') // 要测试的示例的相对地址
|
||||||
|
await page.getByRole('button', { name: /播放/ }).click()
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
await page.locator('#precision').getByText('24.0000')
|
||||||
|
})
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" :precision="4" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="jsx">
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TinyButton,
|
||||||
|
TinyNumberAnimation
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fromVal: 0.0,
|
||||||
|
toVal: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$refs.numberAnimationRef.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="jsx">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
const numberAnimationRef = ref(null)
|
||||||
|
const fromVal = ref(0)
|
||||||
|
const toVal = ref(100000000)
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
numberAnimationRef.value?.play()
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { test, expect } from '@playwright/test'
|
||||||
|
|
||||||
|
test('分隔符', async ({ page }) => {
|
||||||
|
page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误
|
||||||
|
await page.goto('number-animation#separator') // 要测试的示例的相对地址
|
||||||
|
await page.getByRole('button', { name: '播放', exact: true }).click()
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
await page.locator('#separator').getByText('100,000,000')
|
||||||
|
})
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<tiny-number-animation ref="numberAnimationRef" :from="fromVal" :to="toVal" :active="false" />
|
||||||
|
<tiny-button @click="handleClick">播放</tiny-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="jsx">
|
||||||
|
import { TinyButton, TinyNumberAnimation } from '@opentiny/vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TinyButton,
|
||||||
|
TinyNumberAnimation
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fromVal: 0,
|
||||||
|
toVal: 100000000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$refs.numberAnimationRef.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title:
|
||||||
|
---
|
||||||
|
|
||||||
|
# Number Animation 数值动画
|
||||||
|
|
||||||
|
<div>数值播放动画</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title:
|
||||||
|
---
|
||||||
|
|
||||||
|
# Number Animation 数值动画
|
||||||
|
|
||||||
|
<div>Numerical playback animation</div>
|
|
@ -0,0 +1,55 @@
|
||||||
|
export default {
|
||||||
|
column: '1',
|
||||||
|
owner: '',
|
||||||
|
demos: [
|
||||||
|
{
|
||||||
|
demoId: 'basic-usage',
|
||||||
|
name: {
|
||||||
|
'zh-CN': '基本用法',
|
||||||
|
'en-US': 'Basic Usage'
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '通过 <code>from</code> 设置数值动画起始值;<code>to</code>设置目标值。',
|
||||||
|
'en-US': 'Set the starting value of numerical animation through<code>from</code>, <code>to</code>设置目标值.'
|
||||||
|
},
|
||||||
|
codeFiles: ['basic-usage.vue']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
demoId: 'precision',
|
||||||
|
name: {
|
||||||
|
'zh-CN': '精度',
|
||||||
|
'en-US': 'Precision Mode'
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '通过 <code>precision</code> 设置 设定精度。',
|
||||||
|
'en-US': 'Set precision through<code>precision</code>.'
|
||||||
|
},
|
||||||
|
codeFiles: ['precision.vue']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
demoId: 'separator',
|
||||||
|
name: {
|
||||||
|
'zh-CN': '分隔符',
|
||||||
|
'en-US': 'Separator Mode'
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '通过 <code>separator</code> 设置分隔符。',
|
||||||
|
'en-US': 'Set delimiter through<code>separator</code>.'
|
||||||
|
},
|
||||||
|
codeFiles: ['separator.vue']
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
demoId: 'finish-events',
|
||||||
|
name: {
|
||||||
|
'zh-CN': '动画结束事件',
|
||||||
|
'en-US': 'Finish Event'
|
||||||
|
},
|
||||||
|
desc: {
|
||||||
|
'zh-CN': '通过 <code>finish</code> 自定义动画结束后的事件',
|
||||||
|
'en-US': 'Customize the events after the animation ends through<code>finish</code>.'
|
||||||
|
},
|
||||||
|
codeFiles: ['finish-events.vue']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -249,7 +249,8 @@ export const cmpMenus = [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'nameCn': '用户头像', 'name': 'UserHead', 'key': 'user-head' },
|
{ 'nameCn': '用户头像', 'name': 'UserHead', 'key': 'user-head' },
|
||||||
{ 'nameCn': '流程图', 'name': 'Wizard', 'key': 'wizard' }
|
{ 'nameCn': '流程图', 'name': 'Wizard', 'key': 'wizard' },
|
||||||
|
{ 'nameCn': '数值动画', 'name': 'NumberAnimation', key: 'number-animation' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1708,6 +1708,19 @@
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"exclude": false
|
"exclude": false
|
||||||
},
|
},
|
||||||
|
"NumberAnimation": {
|
||||||
|
"path": "vue/src/number-animation/index.ts",
|
||||||
|
"type": "component",
|
||||||
|
"exclude": false,
|
||||||
|
"mode": [
|
||||||
|
"pc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NumberAnimationPc": {
|
||||||
|
"path": "vue/src/number-animation/src/pc.vue",
|
||||||
|
"type": "template",
|
||||||
|
"exclude": false
|
||||||
|
},
|
||||||
"Option": {
|
"Option": {
|
||||||
"path": "vue/src/option/index.ts",
|
"path": "vue/src/option/index.ts",
|
||||||
"type": "component",
|
"type": "component",
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
export const onFinish =
|
||||||
|
({ emit, props, state }) =>
|
||||||
|
() => {
|
||||||
|
state.value = props.to
|
||||||
|
state.animating = false
|
||||||
|
emit('finish')
|
||||||
|
}
|
||||||
|
|
||||||
|
const easeOut = (t: number): number => 1 - (1 - t) ** 5
|
||||||
|
|
||||||
|
export const play =
|
||||||
|
({ props, state, api }) =>
|
||||||
|
() => {
|
||||||
|
animate(state, props, api)
|
||||||
|
}
|
||||||
|
export const animate = (state, props, api) => {
|
||||||
|
state.animating = true
|
||||||
|
state.value = props.from
|
||||||
|
if (props.from !== props.to) {
|
||||||
|
const startTime = performance.now()
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
const current = performance.now()
|
||||||
|
const elapsedTime = Math.min(current - startTime, props.duration)
|
||||||
|
const currentValue = props.from + (props.to - props.from) * easeOut(elapsedTime / props.duration)
|
||||||
|
if (elapsedTime === props.duration) {
|
||||||
|
api.onFinish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.value = currentValue
|
||||||
|
requestAnimationFrame(tick)
|
||||||
|
}
|
||||||
|
tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formattedValue =
|
||||||
|
({ state, props }) =>
|
||||||
|
() => {
|
||||||
|
// 类型检查
|
||||||
|
if (typeof state.value !== 'number' && typeof state.value !== 'string') return
|
||||||
|
if (typeof props.precision !== 'number') return
|
||||||
|
const numValue = Number(state.value)
|
||||||
|
if (isNaN(numValue) || !isFinite(numValue)) return
|
||||||
|
if (numValue === 0) {
|
||||||
|
return numValue.toFixed(props.precision)
|
||||||
|
}
|
||||||
|
let formatValue = numValue.toFixed(props.precision)
|
||||||
|
if (typeof props.separator === 'string' && props.separator !== '') {
|
||||||
|
const [integerPart, decimalPart] = formatValue.split('.')
|
||||||
|
formatValue =
|
||||||
|
integerPart.replace(/(\d)(?=(\d{3})+$)/g, '$1' + props.separator) + (decimalPart ? '.' + decimalPart : '')
|
||||||
|
}
|
||||||
|
return formatValue
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { play, formattedValue, onFinish } from './index'
|
||||||
|
|
||||||
|
export const api = ['state', 'play', 'formattedValue', 'onFinish']
|
||||||
|
export const renderless = (props, { onMounted, computed, reactive }, { emit }) => {
|
||||||
|
const api = {}
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
animating: true,
|
||||||
|
value: props.from,
|
||||||
|
showValue: computed(() => api.formattedValue(state, props))
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.active) {
|
||||||
|
api.play(props, state)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Object.assign(api, {
|
||||||
|
state,
|
||||||
|
play: play({ props, state, api }),
|
||||||
|
formattedValue: formattedValue({ state, props }),
|
||||||
|
onFinish: onFinish({ emit, props, state })
|
||||||
|
})
|
||||||
|
|
||||||
|
return api
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
@import '../custom.less';
|
||||||
|
@import './vars.less';
|
||||||
|
|
||||||
|
@number-animation-item-prefix-cls: ~'@{css-prefix}number-animation';
|
||||||
|
|
||||||
|
.@{number-animation-item-prefix-cls} {
|
||||||
|
.inject-NumberAnimation-vars();
|
||||||
|
font-size: var(--tv-NumberAnimation-font-size);
|
||||||
|
font-weight: var(--tv-NumberAnimation-font-weight);
|
||||||
|
margin-bottom: var(--tv-NumberAnimation-margin-bottom);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
.inject-NumberAnimation-vars() {
|
||||||
|
// 数字内容下间距
|
||||||
|
--tv-NumberAnimation-margin-bottom: 20px;
|
||||||
|
// 数字内容字体粗细
|
||||||
|
--tv-NumberAnimation-font-weight: var(--tv-font-weight-regular);
|
||||||
|
// 数字内容字体
|
||||||
|
--tv-NumberAnimation-font-size: var(--tv-font-size-heading-lg);
|
||||||
|
}
|
|
@ -118,7 +118,7 @@
|
||||||
font-size: var(--tv-Table-icon-font-size);
|
font-size: var(--tv-Table-icon-font-size);
|
||||||
border-radius: var(--tv-Table-check-icon-border-radius);
|
border-radius: var(--tv-Table-check-icon-border-radius);
|
||||||
& path:last-child{
|
& path:last-child{
|
||||||
fill: var(--tv-Table-border-color);
|
fill: var(--tv-Table-icon-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
& path:first-child {
|
& path:first-child {
|
||||||
|
|
|
@ -28,7 +28,9 @@
|
||||||
// 表格单元格字体大小
|
// 表格单元格字体大小
|
||||||
--tv-Table-td-font-size: var(--tv-font-size-default, 14px);
|
--tv-Table-td-font-size: var(--tv-font-size-default, 14px);
|
||||||
// 表格边框颜色
|
// 表格边框颜色
|
||||||
--tv-Table-border-color: var(--tv-color-border-divider, #f0f0f0);
|
--tv-Table-border-color: var(--tv-color-border-divider);
|
||||||
|
// 表格复选框边框颜色
|
||||||
|
--tv-Table-icon-border-color: var(--tv-color-border);
|
||||||
// 表头背景颜色
|
// 表头背景颜色
|
||||||
--tv-Table-thead-bg-color: var(--tv-color-bg-header, #f5f5f5);
|
--tv-Table-thead-bg-color: var(--tv-color-bg-header, #f5f5f5);
|
||||||
// 表格图标字体大小
|
// 表格图标字体大小
|
||||||
|
|
|
@ -137,6 +137,7 @@
|
||||||
"@opentiny/vue-month-table": "workspace:~",
|
"@opentiny/vue-month-table": "workspace:~",
|
||||||
"@opentiny/vue-nav-menu": "workspace:~",
|
"@opentiny/vue-nav-menu": "workspace:~",
|
||||||
"@opentiny/vue-notify": "workspace:~",
|
"@opentiny/vue-notify": "workspace:~",
|
||||||
|
"@opentiny/vue-number-animation": "workspace:~",
|
||||||
"@opentiny/vue-numeric": "workspace:~",
|
"@opentiny/vue-numeric": "workspace:~",
|
||||||
"@opentiny/vue-option": "workspace:~",
|
"@opentiny/vue-option": "workspace:~",
|
||||||
"@opentiny/vue-option-group": "workspace:~",
|
"@opentiny/vue-option-group": "workspace:~",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { describe } from 'vitest'
|
||||||
|
|
||||||
|
describe('PC Mode', () => {})
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2022 - present TinyVue Authors.
|
||||||
|
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license.
|
||||||
|
*
|
||||||
|
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||||
|
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import NumberAnimation from './src/index'
|
||||||
|
import '@opentiny/vue-theme/number-animation/index.less'
|
||||||
|
import { version } from './package.json'
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
NumberAnimation.install = function (Vue) {
|
||||||
|
Vue.component(NumberAnimation.name, NumberAnimation)
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation.version = version
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (process.env.BUILD_TARGET === 'runtime') {
|
||||||
|
if (typeof window !== 'undefined' && window.Vue) {
|
||||||
|
NumberAnimation.install(window.Vue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NumberAnimation
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "@opentiny/vue-number-animation",
|
||||||
|
"type": "module",
|
||||||
|
"version": "3.20.0",
|
||||||
|
"description": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"sideEffects": false,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "pnpm -w build:ui $npm_package_name",
|
||||||
|
"//postversion": "pnpm build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@opentiny/vue-button": "workspace:~",
|
||||||
|
"@opentiny/vue-common": "workspace:~",
|
||||||
|
"@opentiny/vue-modal": "workspace:~",
|
||||||
|
"@opentiny/vue-renderless": "workspace:~",
|
||||||
|
"@opentiny/vue-statistic": "workspace:~",
|
||||||
|
"@opentiny/vue-theme": "workspace:~"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@opentiny-internal/vue-test-utils": "workspace:*",
|
||||||
|
"vitest": "catalog:"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common'
|
||||||
|
import template from 'virtual-template?pc'
|
||||||
|
|
||||||
|
export const $constants = {
|
||||||
|
PREFIX: 'tiny-number-animation'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const numberAnimationProps = {
|
||||||
|
...$props,
|
||||||
|
_constants: {
|
||||||
|
type: Object,
|
||||||
|
default: () => $constants
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
precision: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
type: String,
|
||||||
|
default: ','
|
||||||
|
},
|
||||||
|
from: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
type: Number,
|
||||||
|
default: 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: $prefix + 'NumberAnimation',
|
||||||
|
props: numberAnimationProps,
|
||||||
|
setup(props, context) {
|
||||||
|
return $setup({ props, context, template })
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!--
|
||||||
|
* Copyright (c) 2022 - present TinyVue Authors.
|
||||||
|
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license.
|
||||||
|
*
|
||||||
|
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||||
|
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="tiny-number-animation" ref="numberAnimationInstRef">
|
||||||
|
{{ state.showValue }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { renderless, api } from '@opentiny/vue-renderless/number-animation/vue'
|
||||||
|
import { props, setup, defineComponent } from '@opentiny/vue-common'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['finish'],
|
||||||
|
props: [...props, 'to', 'precision', 'separator', 'from', 'duration', 'active'],
|
||||||
|
setup(props, context) {
|
||||||
|
return setup({ props, context, renderless, api })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
Reference in New Issue