Skip to content

Commit

Permalink
feat(numeric): [numeric] add step strategy of props (#2584)
Browse files Browse the repository at this point in the history
* feat(numeric): [numeric] add step strategy of props

* fix(numeric): [numeric] modify condition

* fix(numeric): [numeric] modify description

* fix(numeric): [numeric] modify review

* fix(numeric): [numeric] modify review
  • Loading branch information
James-9696 authored Dec 3, 2024
1 parent 3018041 commit 5f7a69f
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 35 deletions.
20 changes: 17 additions & 3 deletions examples/sites/demos/apis/numeric.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,12 @@ export default {
},
{
name: 'step',
type: 'number',
type: 'number | string | IStepStrategy',
typeAnchorName: 'IStepStrategy',
defaultValue: '1',
meta: {
stable: '3.20.0'
},
desc: {
'zh-CN': '步长',
'en-US': 'Increment or decrement value each time'
Expand All @@ -309,13 +313,13 @@ export default {
'en-US': 'Whether to enter only multiples of step'
},
mode: ['pc', 'mobile', 'mobile-first'],
pcDemo: 'step',
pcDemo: 'about-step',
mobileDemo: 'step',
mfDemo: ''
},
{
name: 'strict-input',
type: 'Boolean',
type: 'boolean',
defaultValue: '',
desc: {
'zh-CN': '严格控制输入,包含合法性输入与小数点长度验证,不允许输入超过精度设置',
Expand Down Expand Up @@ -511,6 +515,16 @@ interface INumericFormat {
fractionGroupSize: 0, // 小数部分分组间隔
fractionGroupSeparator: '', // 小数分组分隔符
suffix: '@' // 后置标识
}
`
},
{
name: 'IStepStrategy',
type: 'interface',
code: `
interface IStepStrategy {
value: number | string, // 5 或者 '5'
mode: 'strictly' | 'restore'
}
`
}
Expand Down
34 changes: 32 additions & 2 deletions examples/sites/demos/pc/app/numeric/about-step-composition-api.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
<template>
<tiny-numeric v-model="value" :step="step"></tiny-numeric>
<div class="m-layout">
<div class="m-b10">
<div class="m-b10">1、step 用法</div>
<tiny-numeric v-model="value" :step="step"></tiny-numeric>
<br />
<tiny-numeric v-model="restrictValue" :step="stepRestrictly"></tiny-numeric>
</div>
<div>
<div class="m-b10">2、step-strictly 用法</div>
<tiny-numeric v-model="valueStep" :step="step.value" step-strictly></tiny-numeric>
</div>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { TinyNumeric } from '@opentiny/vue'
const value = ref(0)
const step = ref(2)
const restrictValue = ref(0)
const step = ref({
value: 5,
mode: 'restore'
})
const stepRestrictly = ref({
value: 5,
mode: 'strictly'
})
const valueStep = ref(0)
</script>

<style scoped>
.m-layout {
display: flex;
flex-direction: column;
}
.m-b10 {
margin-bottom: 10px;
}
</style>
46 changes: 35 additions & 11 deletions examples/sites/demos/pc/app/numeric/about-step.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,40 @@ import { test, expect } from '@playwright/test'
test('步长', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('numeric#about-step')

const step = page.locator('#about-step')
const increase = page.locator('div:nth-child(2) > .tiny-numeric-base > .tiny-numeric__increase')
const input = page.getByRole('spinbutton')
const increaseBtn = page.locator('.tiny-numeric__increase')
const decreaseBtn = page.locator('.tiny-numeric__decrease')
const value = Number(await input.inputValue())
const step = 2
await decreaseBtn.click()
const decreasedVal = Number(await input.inputValue())
expect(value).toEqual(decreasedVal + step)
await increaseBtn.click()
const increasedVal = Number(await input.inputValue())
expect(decreasedVal).toEqual(increasedVal - step)
await increase.first().click()
await step.getByRole('spinbutton').first().click()
await step.getByRole('spinbutton').first().fill('51')
await page
.locator('div')
.filter({ hasText: /^1step $/ })
.first()
.click()
const value = Number(await input.first().inputValue())
expect(value).toEqual(5)

await increase.nth(1).click()
await step.getByRole('spinbutton').nth(1).click()
await step.getByRole('spinbutton').nth(1).fill('21')
await page
.locator('div')
.filter({ hasText: /^1step $/ })
.first()
.click()
const valueNth = Number(await input.nth(1).inputValue())
expect(valueNth).toEqual(20)

const strict = page.locator('div:nth-child(2) > .tiny-numeric > .tiny-numeric-base > .tiny-numeric__increase')
await strict.click()
await step.getByRole('spinbutton').nth(2).click()
await step.getByRole('spinbutton').nth(2).fill('29')
await page
.locator('div')
.filter({ hasText: /^2step-strictly $/ })
.first()
.click()
const valueRestrict = Number(await input.nth(2).inputValue())
expect(valueRestrict).toEqual(30)
})
34 changes: 32 additions & 2 deletions examples/sites/demos/pc/app/numeric/about-step.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<template>
<tiny-numeric v-model="value" :step="step"></tiny-numeric>
<div class="m-layout">
<div class="m-b10">
<div class="m-b10">1、step 用法</div>
<tiny-numeric v-model="value" :step="step"></tiny-numeric>
<br />
<tiny-numeric v-model="restrictValue" :step="stepRestrictly"></tiny-numeric>
</div>
<div>
<div class="m-b10">2、step-strictly 用法</div>
<tiny-numeric v-model="valueStep" :step="step.value" step-strictly></tiny-numeric>
</div>
</div>
</template>

<script lang="ts">
Expand All @@ -12,8 +23,27 @@ export default {
data() {
return {
value: 0,
step: 2
restrictValue: 0,
valueStep: 0,
step: {
value: 5,
mode: 'restore'
},
stepRestrictly: {
value: 5,
mode: 'strictly'
}
}
}
}
</script>

<style scoped>
.m-layout {
display: flex;
flex-direction: column;
}
.m-b10 {
margin-bottom: 10px;
}
</style>
6 changes: 4 additions & 2 deletions examples/sites/demos/pc/app/numeric/webdoc/numeric.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ export default {
'en-US': 'Step'
},
desc: {
'zh-CN': '可通过<code>step</code>属性设置计数器的加减数值。',
'en-US': 'Set the addition and subtraction values of the counter through the<code>step</code>attribute.'
'zh-CN':
'可通过<code>step</code>属性设置计数器的加减数值及<code>mode</code>模式为<code>restore</code>、<code>strictly</code>的用法,<code>step-strictly</code>属性设置只能输入 step 的倍数',
'en-US':
'The addition and subtraction values of the counter can be set through the<code>step</code>attribute, and the<code>mode</code>can be used for<code>restore</code>and<code>strictly</code>modes. The<code>step strictly</code>attribute can only input multiples of step'
},
codeFiles: ['about-step.vue']
},
Expand Down
45 changes: 31 additions & 14 deletions packages/renderless/src/numeric/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,26 @@ export const getPrecision =

export const internalIncrease =
({ api, state }: Pick<INumericRenderlessParams, 'api' | 'state'>) =>
({ val, step }: { val: number; step: number }): string => {
({ val, step }: { val: number | string; step: number | string }): string => {
const decimal = api.getDecimal(val)

if (decimal.isNaN() && val !== undefined) {
return state.currentValue
}

return decimal.add(step).toString()
const addValue = decimal.add(step).toString()
return addValue
}

export const internalDecrease =
({ api, state }: Pick<INumericRenderlessParams, 'api' | 'state'>) =>
({ val, step }: { val: number; step: number }): string | number => {
({ val, step }: { val: number | string; step: number | string }): string | number => {
const decimal = api.getDecimal(val)

if (decimal.isNaN() && val !== undefined) {
return state.currentValue
}

return decimal.add(`-${step}`).toString()
const decreaseValue = decimal.add(`-${step}`).toString()
return decreaseValue
}

export const increase =
Expand All @@ -121,8 +121,10 @@ export const increase =
if (value.toString().includes('e')) {
return
}

let newVal = api.internalIncrease({ val: value, step: props.step })
let newVal = api.internalIncrease({
val: value,
step: props.step?.value ?? props.step
})

if (!props.circulate || !isFinite(props.max) || !isFinite(props.min)) {
api.setCurrentValue(newVal)
Expand Down Expand Up @@ -151,8 +153,10 @@ export const decrease =
if (value.toString().includes('e')) {
return
}

let newVal = api.internalDecrease({ val: value, step: props.step })
let newVal = api.internalDecrease({
val: value,
step: props.step?.value ?? props.step
})

if (!props.circulate || !isFinite(props.max) || !isFinite(props.min)) {
api.setCurrentValue(newVal)
Expand Down Expand Up @@ -302,6 +306,14 @@ export const setCurrentValue =
if (validateEvent) {
dispatch(constants.COMPONENT_NAME, constants.EVENT_NAME.change, [state.currentValue])
}

if (props.step instanceof Object && props.step?.mode === 'restore' && props.step?.value) {
const stepValue = Number(props.step.value)
if (stepValue > 1 && newVal % stepValue !== 0) {
state.currentValue = oldVal
state.userInput = oldVal
}
}
}
}

Expand Down Expand Up @@ -351,10 +363,14 @@ export const handleInputChange =
({ api, state, props }: Pick<INumericRenderlessParams, 'api' | 'state' | 'props'>) =>
(event: Event): void => {
const value = event.target?.value === '-' ? 0 : event.target?.value
if (props.stepStrictly) {
if (props.stepStrictly || (typeof props.step === 'object' && props.step?.mode === 'strictly')) {
const previousValue = Number((props.mouseWheel ? state.displayValue : props.modelValue) || 0)
if (Math.abs(previousValue - value) % Number(props.step) === 0) return api.setCurrentValue(value)
const step = Number(props.step)
if (
Math.abs(previousValue - value) % Number(props.step) === 0 ||
Math.abs(previousValue - value) % Number(props.step.value) === 0
)
return api.setCurrentValue(value)
const step = Number(props.step) || Number(props.step.value)
const difference = value - previousValue
const sign = difference >= 0 ? 1 : -1
return api.setCurrentValue(sign * Math.round(Math.abs(difference) / step) * step + previousValue)
Expand Down Expand Up @@ -437,7 +453,8 @@ export const displayValue =
export const getNumPecision =
({ api, props }: Pick<INumericRenderlessParams, 'api' | 'props'>) =>
(): number => {
const stepPrecision = api.getPrecision(props.step)
const stepValue = props.step?.value ?? props.step
const stepPrecision = api.getPrecision(stepValue)

if (props.precision !== undefined) {
return props.precision
Expand Down
2 changes: 1 addition & 1 deletion packages/vue/src/numeric/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const numericProps = {
},
size: String,
step: {
type: [Number, String],
type: [Number, String, Object],
default: 1
},
stepStrictly: {
Expand Down

0 comments on commit 5f7a69f

Please sign in to comment.