Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(numeric): [numeric] add step strategy of props #2584

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

James-9696
Copy link
Collaborator

@James-9696 James-9696 commented Dec 2, 2024

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced step property to accept more complex configurations including numbers, strings, and objects.
    • Introduced step-strictly functionality to restrict inputs to multiples of the step value.
    • Added new interfaces for better type management.
  • Improvements

    • Updated layouts and examples for better user experience and clarity on tiny-numeric component usage.
    • Improved documentation for about-step demo to clarify usage of modes.
  • Bug Fixes

    • Enhanced input handling and validation for numeric values to ensure consistency and accuracy.

Copy link

coderabbitai bot commented Dec 2, 2024

Walkthrough

The changes in this pull request primarily focus on enhancing the numeric component's API and related Vue components. Modifications include updates to the step property to accept more complex types, the introduction of new interfaces for better type management, and a restructuring of several Vue components to support these enhancements. Additionally, the test cases for the numeric step functionality have been revised to accommodate the new configurations, ensuring comprehensive validation of the component's behavior.

Changes

File Path Change Summary
examples/sites/demos/apis/numeric.js Updated step property type to `number
examples/sites/demos/pc/app/numeric/about-step-composition-api.vue Expanded template layout, transformed step variable to an object, added stepRestrictly and restrictValue variables.
examples/sites/demos/pc/app/numeric/about-step.spec.ts Revised test logic to use dynamic interactions with multiple spinbuttons, updated expected values and locators.
examples/sites/demos/pc/app/numeric/about-step.vue Updated template structure, modified step variable to an object, added restrictValue and valueStep properties.
examples/sites/demos/pc/app/numeric/webdoc/numeric.js Expanded descriptions for demo entries, particularly for about-step, to clarify mode attributes.
packages/renderless/src/numeric/index.ts Updated internalIncrease and internalDecrease functions to accept step as `number
packages/vue/src/numeric/src/index.ts Changed step property type from [Number, String] to [Number, String, Object] to allow for object types.

Possibly related PRs

  • fix(steps): [steps] Added the visibleNum prop. #2542: Introduces a new visibleNum property to the steps component, which is directly related to the changes made in the retrieved PR that updates the visible-num property in the steps API.
  • feat(steps): [steps] Adapting to the Default Theme #2549: The changes in the main PR regarding the numeric component's API and the addition of new interfaces may relate to the styling and theming adjustments in the steps component, as both PRs focus on enhancing component functionality and visual consistency within the framework.

Suggested reviewers

  • zzcr

Poem

In the meadow, numbers play,
With steps that dance and sway.
From strings to objects, oh what fun,
New paths for all, each and every one!
With layouts bright and tests anew,
Our tiny-numeric shines for you! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the enhancement New feature or request label Dec 2, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (9)
examples/sites/demos/pc/app/numeric/about-step.spec.ts (4)

6-7: Use more specific selectors for locators

The locators for step and increase use CSS selectors that may be brittle and prone to breaking if the DOM structure changes.

Consider using roles or data attributes for more resilient selectors. For example:

-const step = page.locator('#about-step')
-const increase = page.locator('div:nth-child(2) > .tiny-numeric-base > .tiny-numeric__increase')
+const step = page.locator('[data-test-id="about-step"]')
+const increase = page.locator('[data-test-id="increase-button"]')

9-11: Add assertions to verify the initial state before actions

Before performing actions like clicks and fills, it's good practice to assert the initial state to ensure the test is reliable.

Consider adding assertions like:

expect(await input.first().inputValue()).toEqual('0')

20-22: Consistent use of locators

The locator for increase uses increase.nth(1), while for step, it uses step.getByRole('spinbutton').nth(1). This inconsistency can lead to confusion.

Consider using consistent locator strategies for better readability.


31-33: Potential flaky test due to hardcoded selectors

The selector 'div:nth-child(2) > .tiny-numeric > .tiny-numeric-base > .tiny-numeric__increase' can be fragile.

Prefer using more robust selectors, such as data attributes or roles.

packages/renderless/src/numeric/index.ts (1)

456-458: Typo in function name getNumPecision

The function name getNumPecision appears to have a typo.

Consider renaming it to getNumPrecision for clarity.

examples/sites/demos/pc/app/numeric/about-step-composition-api.vue (2)

11-11: Inconsistent use of step property

In the third tiny-numeric, :step="step.value" is used with step-strictly prop, but stepStrictly is also set in stepRestrictly.

Consider using a consistent approach by either passing the entire step object or adjusting the configuration.


33-41: Scoped styles affecting global elements

The styles defined may unintentionally affect other components.

Ensure the styles are properly scoped to prevent side effects.

examples/sites/demos/pc/app/numeric/about-step.vue (1)

11-11: Potential confusion with step usage

Using :step="step.value" along with step-strictly might cause confusion.

Consider passing the entire step object if it includes mode configurations, or clarify the intent.

examples/sites/demos/apis/numeric.js (1)

521-528: Consider adding JSDoc comments to the IStepStrategy interface.

While the interface is well-structured, adding JSDoc comments would improve the API documentation:

 interface IStepStrategy {
+  /** The step value to be used */
   value: string | number,
+  /** The step mode: 'strictly' enforces step multiples, 'restore' adjusts to nearest step */
   mode: 'strictly' | 'restore'
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 69ebb7c and 6874d00.

📒 Files selected for processing (7)
  • examples/sites/demos/apis/numeric.js (3 hunks)
  • examples/sites/demos/pc/app/numeric/about-step-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/numeric/about-step.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/numeric/about-step.vue (2 hunks)
  • examples/sites/demos/pc/app/numeric/webdoc/numeric.js (1 hunks)
  • packages/renderless/src/numeric/index.ts (6 hunks)
  • packages/vue/src/numeric/src/index.ts (1 hunks)
🔇 Additional comments (8)
examples/sites/demos/pc/app/numeric/about-step.spec.ts (1)

17-18: Ensure correct value after increment

The test expects the value to be 5, but without prior context, it's unclear if 5 is the correct expected value after the increment.

Please verify that the step configuration and initial value result in 5 after one increment.

examples/sites/demos/pc/app/numeric/about-step-composition-api.vue (2)

5-7: Verify binding of v-model properties

The tiny-numeric components are using v-model="value" and v-model="restrictValue", but the variables need to be defined.

Ensure that value and restrictValue are declared in the script section.


21-30: Unused variables in script

Variables restrictValue and valueStep are declared but may not be properly initialized or used.

Confirm that these variables are correctly initialized and bound to the template.

examples/sites/demos/pc/app/numeric/about-step.vue (2)

5-7: Ensure all v-model bindings have corresponding data properties

The tiny-numeric components use v-model="value", v-model="restrictValue", and v-model="valueStep". Verify that these are defined.

Check the data section to confirm these properties are declared.


26-35: Validate the structure of step and stepRestrictly objects

Ensure that the step and stepRestrictly objects have the correct structure and that their properties are being used appropriately.

Confirm that these objects align with the expected API of the tiny-numeric component.

examples/sites/demos/pc/app/numeric/webdoc/numeric.js (1)

38-41: LGTM! Documentation updates are clear and comprehensive.

The description accurately reflects the new step functionality, including:

  • New mode options (restore and strictly)
  • Introduction of step-strictly attribute
examples/sites/demos/apis/numeric.js (2)

292-297: LGTM! Step property enhancement is well-defined.

The type expansion and version metadata addition are appropriate for tracking the new functionality.


292-297: Verify integration with existing numeric implementations.

The new step strategy feature introduces significant changes to the numeric component's behavior.

Also applies to: 521-528

✅ Verification successful

Based on the comprehensive search results, I can now provide a final response:

The step strategy feature is well-integrated and properly documented.

The verification shows:

  • The IStepStrategy interface is properly defined and documented in the API
  • Multiple demo implementations showcase the step functionality working correctly:
    • Basic step usage
    • Step-strictly mode
    • Step with different modes (restore/strictly)
  • Tests verify the step functionality for both button clicks and keyboard controls
  • The feature is consistently implemented across PC, mobile, and mobile-first versions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify existing numeric implementations won't break with new step strategy

# Search for current numeric component usage patterns
echo "Checking current numeric component usage patterns..."
rg -l "(?s)<tiny-numeric[^>]*step=" --type vue

# Search for potential conflicts with existing step implementations
echo "Checking for potential conflicts..."
rg -l "(?s)<tiny-numeric[^>]*step=.*?mode=" --type vue

Length of output: 357


Script:

#!/bin/bash
# Let's try a different approach to find numeric component usage patterns
# First, let's find all potential UI files
echo "Finding all potential UI files..."
fd -e js -e jsx -e ts -e tsx -e vue

# Then search for numeric component usage in these files
echo "Checking numeric component usage patterns..."
rg -l "tiny-numeric"

# Look for step-related implementations
echo "Checking step-related implementations..."
rg -C 3 "step.*?=" 

# Check the numeric component's implementation
echo "Examining numeric component implementation..."
fd -t f numeric

Length of output: 74079


Script:

#!/bin/bash
# Let's search for numeric component implementations and step-related code
echo "Searching for numeric component implementations..."
rg -C 5 "IStepStrategy" 

echo "Checking numeric component usage..."
rg -C 5 "tiny-numeric.*?step="

echo "Looking for step-related code..."
fd -t f numeric | xargs rg -C 5 "step"

Length of output: 26285

Comment on lines 156 to 159
let newVal = api.internalDecrease({
val: value,
step: props.step.value ? Number(props.step.value) : props.step
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consistent handling of step in decrease function

Same issue as in increase function; ensure props.step is handled correctly.

Apply the same fix as above for the decrease function.

Comment on lines 87 to 93
({ val, step }: { val: number; 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle string inputs for step parameter

The internalIncrease function now accepts step as number | string, but decimal.add(step) may not handle strings properly.

Ensure step is converted to a number before using it in calculations. Apply this fix:

const addValue = decimal.add(Number(step)).toString()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
({ val, step }: { val: number; 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
({ val, step }: { val: number; step: number | string }): string => {
const decimal = api.getDecimal(val)
if (decimal.isNaN() && val !== undefined) {
return state.currentValue
}
const addValue = decimal.add(Number(step)).toString()
return addValue

Comment on lines 98 to 106
({ val, step }: { val: number; 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle string inputs for step parameter in internalDecrease

Similar to internalIncrease, internalDecrease should ensure step is a number.

Convert step to a number before using it:

const decreaseValue = decimal.add(-Number(step)).toString()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
({ val, step }: { val: number; 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
({ val, step }: { val: number; step: number | string }): string | number => {
const decimal = api.getDecimal(val)
if (decimal.isNaN() && val !== undefined) {
return state.currentValue
}
const decreaseValue = decimal.add(-Number(step)).toString()
return decreaseValue

packages/renderless/src/numeric/index.ts Show resolved Hide resolved
Comment on lines 366 to 373
if (props.stepStrictly || 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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect modulus operation with props.step

In the condition, Math.abs(previousValue - value) % Number(props.step) assumes props.step is always a number.

Ensure props.step is converted properly, and handle cases where props.step is an object:

const stepValue = typeof props.step === 'object' ? Number(props.step.value) : Number(props.step)
if (Math.abs(previousValue - value) % stepValue === 0) {
  return api.setCurrentValue(value)
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (props.stepStrictly || 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)
if (props.stepStrictly || props.step?.mode === 'strictly') {
const previousValue = Number((props.mouseWheel ? state.displayValue : props.modelValue) || 0)
const stepValue = typeof props.step === 'object' ? Number(props.step.value) : Number(props.step)
if (Math.abs(previousValue - value) % stepValue === 0) {
return api.setCurrentValue(value)
}
const step = Number(props.step) || Number(props.step.value)

Comment on lines +97 to 99
type: [Number, String, Object],
default: 1
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Update type definitions for step prop

The step prop now includes Object in its type without a corresponding interface or type definition.

Define an interface for the step object to ensure type safety and maintainability.

interface StepStrategy {
  value: number | string
  mode: 'restore' | 'strictly'
}

Then, update the prop type:

step: {
  type: [Number, String, Object] as PropType<number | string | StepStrategy>,
  default: 1
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6874d00 and 292c36f.

📒 Files selected for processing (1)
  • packages/renderless/src/numeric/index.ts (6 hunks)
🔇 Additional comments (4)
packages/renderless/src/numeric/index.ts (4)

309-316: ⚠️ Potential issue

Improve restore mode validation in setCurrentValue

The current implementation has issues with decimal steps and lacks proper validation.

Apply these improvements:

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

Likely invalid or redundant comment.


87-93: 🛠️ Refactor suggestion

Improve type safety and precision handling in internalIncrease

The function needs better validation and precision handling for string inputs.

Apply this improvement:

 ({ val, step }: { val: number; step: number | string }): string => {
   const decimal = api.getDecimal(val)
   if (decimal.isNaN() && val !== undefined) {
     return state.currentValue
   }
-  const addValue = decimal.add(step).toString()
+  const stepValue = typeof step === 'string' ? parseFloat(step) : step
+  if (isNaN(stepValue)) {
+    return state.currentValue
+  }
+  const addValue = decimal.add(stepValue).toString()
   return addValue
 }

Likely invalid or redundant comment.


98-106: 🛠️ Refactor suggestion

Improve string handling in internalDecrease

Similar to internalIncrease, the function needs better string handling.

Apply this improvement:

 ({ val, step }: { val: number; step: number | string }): string | number => {
   const decimal = api.getDecimal(val)
   if (decimal.isNaN() && val !== undefined) {
     return state.currentValue
   }
-  const decreaseValue = decimal.add(`-${step}`).toString()
+  const stepValue = typeof step === 'string' ? parseFloat(step) : step
+  if (isNaN(stepValue)) {
+    return state.currentValue
+  }
+  const decreaseValue = decimal.add(-stepValue).toString()
   return decreaseValue
 }

Likely invalid or redundant comment.


Line range hint 1-24: Verify usage of new step object structure

The changes introduce a new object structure for the step property. We should verify all usages across the codebase.

Comment on lines 124 to 127
let newVal = api.internalIncrease({
val: value,
step: props.step.value ? Number(props.step.value) : props.step
})
Copy link

@coderabbitai coderabbitai bot Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type safety checks for step object access

Both increase and decrease functions need safer type checking when accessing step.value.

Apply this improvement to both functions:

 let newVal = api.internalIncrease({
   val: value,
-  step: props.step.value ? Number(props.step.value) : props.step
+  step: typeof props.step === 'object' && props.step?.value !== undefined
+    ? Number(props.step.value)
+    : Number(props.step)
 })

Also applies to: 156-159

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props.step.value取值是应该要有容错措施,先判断props.step是不是一个对象

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zzcr,感谢您的理解和确认。是的,在访问props.step.value之前,应该先判断props.step是否是一个对象,以提高代码的健壮性。

(^-^)/


✏️ Learnings added
Learnt from: zzcr
PR: opentiny/tiny-vue#2584
File: packages/renderless/src/numeric/index.ts:124-127
Timestamp: 2024-12-02T08:56:05.048Z
Learning: 在`packages/renderless/src/numeric/index.ts`文件中,在访问`props.step.value`之前,应先判断`props.step`是否为对象,以确保容错处理。

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@@ -437,7 +453,7 @@
export const getNumPecision =
({ api, props }: Pick<INumericRenderlessParams, 'api' | 'props'>) =>
(): number => {
const stepPrecision = api.getPrecision(props.step)
const stepPrecision = api.getPrecision(props.step.value || props.step)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add type safety to precision calculation

The function needs proper type checking before accessing step.value.

Apply this improvement:

-const stepPrecision = api.getPrecision(props.step.value || props.step)
+const stepValue = typeof props.step === 'object' && props.step?.value !== undefined
+  ? props.step.value
+  : props.step
+const stepPrecision = api.getPrecision(stepValue)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const stepPrecision = api.getPrecision(props.step.value || props.step)
const stepValue = typeof props.step === 'object' && props.step?.value !== undefined
? props.step.value
: props.step
const stepPrecision = api.getPrecision(stepValue)

Comment on lines 366 to 373
if (props.stepStrictly || 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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify step validation logic in handleInputChange

The current implementation has duplicate calculations and potential undefined access.

Apply these improvements:

-if (props.stepStrictly || props.step.mode === 'strictly') {
+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 ||
-    Math.abs(previousValue - value) % Number(props.step.value) === 0
-  )
+  const stepValue = typeof props.step === 'object' ? Number(props.step.value) : Number(props.step)
+  if (!isNaN(stepValue) && Math.abs(previousValue - value) % stepValue === 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)
+  return api.setCurrentValue(sign * Math.round(Math.abs(difference) / stepValue) * stepValue + previousValue)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (props.stepStrictly || 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)
if (props.stepStrictly || (typeof props.step === 'object' && props.step?.mode === 'strictly')) {
const previousValue = Number((props.mouseWheel ? state.displayValue : props.modelValue) || 0)
const stepValue = typeof props.step === 'object' ? Number(props.step.value) : Number(props.step)
if (!isNaN(stepValue) && Math.abs(previousValue - value) % stepValue === 0)
return api.setCurrentValue(value)
const difference = value - previousValue
const sign = difference >= 0 ? 1 : -1
return api.setCurrentValue(sign * Math.round(Math.abs(difference) / stepValue) * stepValue + previousValue)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
examples/sites/demos/apis/numeric.js (1)

322-322: Consider fixing similar type casing inconsistencies.

The type has been correctly updated from 'Boolean' to 'boolean'. However, there are other properties in the file still using 'Boolean' (e.g., 'display-only', 'hide-unit', 'hold-zero', etc.).

Consider updating all Boolean types to lowercase 'boolean' for consistency:

  • 'display-only'
  • 'hide-unit'
  • 'hold-zero'
  • 'model-truncation'
  • 'string-mode'
  • 'tabindex'
  • 'unit-center'
  • 'validate-event'
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 292c36f and 87522ed.

📒 Files selected for processing (1)
  • examples/sites/demos/apis/numeric.js (3 hunks)
🔇 Additional comments (3)
examples/sites/demos/apis/numeric.js (3)

316-316: LGTM! Demo reference updated for consistency.

The pcDemo value has been updated to 'about-step' to maintain consistency with the step property's demo reference.

Let's verify the demo file exists:

✅ Verification successful

Demo reference update verified successfully

The about-step demo files exist at the expected location in examples/sites/demos/pc/app/numeric/, confirming that the pcDemo value update to 'about-step' is correct and properly aligned with the available demo files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of the about-step demo file
fd "about-step" examples/sites/demos/pc/app/numeric/

Length of output: 225


518-527: LGTM! Well-structured interface definitions.

The new interfaces are well-defined:

  • INumericFormat: Comprehensive formatting options with clear descriptions
  • IStepStrategy: Clear structure for the new step configuration with proper type constraints

Let's verify the usage of these interfaces in the codebase:

✅ Verification successful

Both interfaces are properly defined and used within the codebase

The interfaces are well integrated:

  • INumericFormat is used as a type definition and referenced in documentation
  • IStepStrategy is correctly used as a union type (number | string | IStepStrategy) for configuration options
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usage of the new interfaces
echo "Checking INumericFormat usage:"
rg "INumericFormat" --type ts
echo "Checking IStepStrategy usage:"
rg "IStepStrategy" --type ts

Length of output: 198


Script:

#!/bin/bash
# Let's try searching without type restriction since the file is .js
echo "Checking INumericFormat usage:"
rg "INumericFormat" -A 2
echo -e "\nChecking IStepStrategy usage:"
rg "IStepStrategy" -A 2

Length of output: 1869


292-297: LGTM! Enhanced step property with new type options.

The step property has been expanded to support more flexible configurations through the new IStepStrategy interface. The stability version is properly documented.

Let's verify the usage of the new step property type in demos:

✅ Verification successful

After analyzing the code output, I can see that the new IStepStrategy interface and step property changes are being used correctly in the demos. Specifically, in the "about-step" demo files, there are examples using the step property with both restore and strictly modes:

step: {
  value: 5,
  mode: 'restore'
},
stepRestrictly: {
  value: 5,
  mode: 'strictly'
}

The step property enhancement is properly implemented and demonstrated.

  • The new IStepStrategy interface is correctly referenced in the API documentation
  • The step property is demonstrated with both object notation and simple number values
  • The demos show proper usage of both restore and strictly modes
  • The feature is correctly marked as stable in version 3.20.0
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for examples using the new step strategy
rg -l "step.*=.*{.*value.*mode" examples/sites/demos/pc/app/numeric/

Length of output: 186


Script:

#!/bin/bash
# Search for step property usage in numeric demos with better regex
rg -l 'step\s*[:=]\s*{' examples/sites/demos/pc/app/numeric/

# Also check for any files that might contain the new IStepStrategy interface
rg -l 'IStepStrategy' .

Length of output: 219


Script:

#!/bin/bash
# Search for step property usage in numeric demos with fixed regex
rg 'step[[:space:]]*[:=][[:space:]]*{' examples/sites/demos/pc/app/numeric/

# Check the content of numeric demos directory for any step-related examples
fd . examples/sites/demos/pc/app/numeric/ -t f -x cat {}

Length of output: 35243

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
packages/renderless/src/numeric/index.ts (2)

124-127: Extract common step value logic

The step value extraction logic is duplicated. Consider extracting it into a helper function.

Create a helper function:

+const getStepValue = (step: any): number | string => {
+  return typeof step === 'object' && step?.value !== undefined ? step.value : step
+}

export const increase =
  ({ api, props, state }: Pick<INumericRenderlessParams, 'api' | 'props' | 'state'>) =>
  (): void => {
    // ...
    let newVal = api.internalIncrease({
      val: value,
-     step: typeof props.step === 'object' && props.step?.value !== undefined ? props.step.value : props.step
+     step: getStepValue(props.step)
    })
    // ...
  }

export const decrease =
  ({ api, props, state }: Pick<INumericRenderlessParams, 'api' | 'props' | 'state'>) =>
  (): void => {
    // ...
    let newVal = api.internalDecrease({
      val: value,
-     step: typeof props.step === 'object' && props.step?.value !== undefined ? props.step.value : props.step
+     step: getStepValue(props.step)
    })
    // ...
  }

Also applies to: 156-159


456-457: Use extracted helper function

This code duplicates the step value extraction logic. Use the proposed getStepValue helper function.

Apply this change:

-const stepValue = typeof props.step === 'object' && props.step?.value !== undefined ? props.step.value : props.step
+const stepValue = getStepValue(props.step)
const stepPrecision = api.getPrecision(stepValue)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 87522ed and 038bc58.

📒 Files selected for processing (1)
  • packages/renderless/src/numeric/index.ts (6 hunks)
🧰 Additional context used
📓 Learnings (1)
packages/renderless/src/numeric/index.ts (1)
Learnt from: zzcr
PR: opentiny/tiny-vue#2584
File: packages/renderless/src/numeric/index.ts:124-127
Timestamp: 2024-12-02T08:56:05.176Z
Learning: 在`packages/renderless/src/numeric/index.ts`文件中,在访问`props.step.value`之前,应先判断`props.step`是否为对象,以确保容错处理。
🔇 Additional comments (2)
packages/renderless/src/numeric/index.ts (2)

309-316: ⚠️ Potential issue

Fix restore mode condition for all step values

The current condition stepValue > 1 fails to handle step values less than or equal to 1.

Apply this fix:

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

Likely invalid or redundant comment.


366-373: 🛠️ Refactor suggestion

Simplify step validation logic

The current implementation has duplicate calculations and potential undefined access.

Apply these improvements:

-if (props.stepStrictly || (typeof props.step === 'object' && props.step?.mode === 'strictly')) {
+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 ||
-    Math.abs(previousValue - value) % Number(props.step.value) === 0
-  )
+  const stepValue = typeof props.step === 'object' ? Number(props.step.value) : Number(props.step)
+  if (!isNaN(stepValue) && Math.abs(previousValue - value) % stepValue === 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)
+  return api.setCurrentValue(sign * Math.round(Math.abs(difference) / stepValue) * stepValue + previousValue)

Likely invalid or redundant comment.

Comment on lines +87 to +93
({ 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type conversion for arithmetic operations

The functions now accept string inputs but don't ensure numeric conversion before arithmetic operations. This could lead to unexpected results.

Apply these changes:

export const internalIncrease =
  ({ api, state }: Pick<INumericRenderlessParams, 'api' | 'state'>) =>
  ({ val, step }: { val: number | string; step: number | string }): string => {
    const decimal = api.getDecimal(val)
    if (decimal.isNaN() && val !== undefined) {
      return state.currentValue
    }
-   const addValue = decimal.add(step).toString()
+   const addValue = decimal.add(Number(step)).toString()
    return addValue
  }

export const internalDecrease =
  ({ api, state }: Pick<INumericRenderlessParams, 'api' | 'state'>) =>
  ({ val, step }: { val: number | string; step: number | string }): string | number => {
    const decimal = api.getDecimal(val)
    if (decimal.isNaN() && val !== undefined) {
      return state.currentValue
    }
-   const decreaseValue = decimal.add(`-${step}`).toString()
+   const decreaseValue = decimal.add(-Number(step)).toString()
    return decreaseValue
  }

Also applies to: 98-106

let newVal = api.internalDecrease({ val: value, step: props.step })
let newVal = api.internalDecrease({
val: value,
step: typeof props.step === 'object' && props.step?.value !== undefined ? props.step.value : props.step
Copy link
Member

@zzcr zzcr Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

机器人给的写法太长了,建议用这个:props.step?.value ?? props.step

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants