Skip to content

feat(search-box): Exception events can be thrown during validation.#50

Open
discreted66 wants to merge 1 commit intoopentiny:mainfrom
discreted66:event0206
Open

feat(search-box): Exception events can be thrown during validation.#50
discreted66 wants to merge 1 commit intoopentiny:mainfrom
discreted66:event0206

Conversation

@discreted66
Copy link
Collaborator

@discreted66 discreted66 commented Feb 6, 2026

feat:校验支持抛出异常事件,并补充相应示例,优化数字区间无单位情况下展示

Summary by CodeRabbit

  • New Features

    • Added validation error event that triggers when user input fails validation rules, providing detailed error feedback.
    • Added demo component showcasing validation error handling.
  • Bug Fixes

    • Fixed unit display in numeric range inputs to show conditionally based on configuration.
  • Chores

    • Updated package version to 3.28.5.

@github-actions github-actions bot added the enhancement New feature or request label Feb 6, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

Walkthrough

A new validation feature is added to the search-box component that validates input tags against regular expressions. Two demo components showcase this functionality with error handling. The core validation logic is implemented in composables with a validate-error event. The package version is bumped to stable release.

Changes

Cohort / File(s) Summary
Demo Components
packages/docs/search-box/validate-error.vue, packages/docs/search-box/validate-error-options-api.vue
Added two new Vue demo components showcasing search-box validation error handling with regexp validators and error message display.
Demo Configuration
packages/docs/search-box/webdoc/search-box.js
Registered a new demo entry "validate-error" with localized metadata and code reference for the demo components.
Core Validation Logic
packages/search-box/src/composables/use-dropdown.ts
Implemented per-tag regexp validation in dropdown creation paths. Invalid tags trigger a validate-error event with payload containing invalid values, field, label, and regexp pattern.
Component API & Templates
packages/search-box/src/pc.vue, packages/search-box/src/components/second-level-panel.vue
Added validate-error event to component emits; updated template logic to conditionally display unit only when present.
Cleanup
packages/search-box/src/composables/use-match.ts
Removed unused loading indicator code from getMatchList function.
Version Update
packages/search-box/package.json
Bumped version from "3.28.5-alpha.0" to "3.28.5" for stable release.

Sequence Diagram

sequenceDiagram
    participant User
    participant SearchBox
    participant Dropdown
    participant Validation
    participant Component

    User->>SearchBox: Input tag value
    SearchBox->>Dropdown: Create tag
    Dropdown->>Validation: Validate tag against regexp
    
    alt Valid Tag
        Validation->>Dropdown: Return valid
        Dropdown->>SearchBox: Apply tag to model
        SearchBox->>Component: Update v-model
    else Invalid Tag
        Validation->>Dropdown: Return invalid with details
        Dropdown->>Component: Emit validate-error event
        Component->>Component: Build error message
        Component->>User: Display error block
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 With whiskers twitching, I craft validation's dance,
Each regexp now catches what slips past our glance,
Tags flutter and spin through the searchbox's domain,
Error events bloom like clover after the rain,
From alpha to stable, the journey's complete—
A hop towards perfection, oh so sweet! 🌟

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title refers to 'Exception events' being thrown during validation, but the changeset actually implements a 'validate-error' event emission feature. The terminology mismatch and vague phrasing ('Exception events') do not clearly convey the actual change. Clarify the title to accurately describe the validate-error event feature, e.g., 'feat(search-box): Add validate-error event for regex validation failures' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🤖 Fix all issues with AI agents
In `@packages/docs/search-box/validate-error.vue`:
- Line 19: The import of Message is unused in this component; remove the unused
symbol by deleting Message from the import statement (the import line that
currently reads import { Message } from "@opentiny/vue") in validate-error.vue
so the component no longer imports an unreferenced symbol.

In `@packages/search-box/src/composables/use-dropdown.ts`:
- Around line 222-229: When all tags fail regex validation the code currently
emits the validate-error with invalidTags but doesn't clear the input because
updateModelValue/newTagUpdateModelValue aren't called; after emitting the error
in the block that checks invalidTags.length > 0 (where emit('validate-error', {
invalidValues: invalidTags, field: prevItem.field, label: prevItem.label,
regexp: regexp.toString() }) is called), invoke resetInput(state) so the input
is cleared when no tag updates occur (ensure this happens only in the path where
tagList validation produced only invalidTags and no
updateModelValue/newTagUpdateModelValue calls were made).
- Around line 210-229: The regexp used in the per-tag validation (variable
regexp) is stateful when it has the g or y flags; reset regexp.lastIndex = 0
before each call to regexp.test() in the tagged path (the loop that iterates
tagList and calls newTagUpdateModelValue(prevItem, propItem, tag)) and also
before any other uses (e.g., the unlabeled path where
regexp.test(state.inputValue) is used during items.find); alternatively
construct a fresh RegExp instance for each test (new RegExp(regexp)) to avoid
shared lastIndex, ensuring the emit('validate-error', {...}) behavior remains
unchanged.
🧹 Nitpick comments (2)
packages/search-box/src/composables/use-dropdown.ts (1)

261-286: Duplicated validation logic — consider extracting a helper.

The validation block here (lines 263–281) is nearly identical to lines 212–229. The only differences are the update function called and the item reference. A shared helper would reduce duplication and ensure both paths stay in sync.

♻️ Sketch of a shared helper
+  const validateAndUpdate = (
+    tagList: string[],
+    regexp: RegExp | undefined,
+    item: any,
+    updateFn: (tag: string) => void
+  ) => {
+    if (regexp) {
+      const invalidTags: string[] = []
+      for (const tag of tagList) {
+        regexp.lastIndex = 0
+        if (regexp.test(tag)) {
+          updateFn(tag)
+        } else {
+          invalidTags.push(tag)
+        }
+      }
+      if (invalidTags.length > 0) {
+        emit('validate-error', {
+          invalidValues: invalidTags,
+          field: item.field,
+          label: item.label,
+          regexp: regexp.toString()
+        })
+      }
+    } else {
+      for (const tag of tagList) {
+        updateFn(tag)
+      }
+    }
+  }

Then use it in both paths:

// Labeled path
validateAndUpdate(tagList, regexp, prevItem, (tag) => newTagUpdateModelValue(prevItem, propItem, tag))

// Unlabeled path
validateAndUpdate(tagList, regexp, currentItem, (tag) => updateModelValue(currentItem, {}, label, tag))
packages/docs/search-box/validate-error.vue (1)

57-64: Error message is never cleared after successful input.

Once errorMessage is set, it persists indefinitely — even after the user successfully adds valid tags. For a demo, consider clearing it (e.g., on @change or with a timer) so it doesn't mislead users into thinking the error is still active.


<script setup lang="ts">
import { ref, reactive } from "vue";
import { Message } from "@opentiny/vue";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unused import: Message is imported but never used.

Message from @opentiny/vue is imported but not referenced anywhere in this component.

🧹 Remove unused import
-import { ref, reactive } from "vue";
-import { Message } from "@opentiny/vue";
+import { ref, reactive } from "vue";
🤖 Prompt for AI Agents
In `@packages/docs/search-box/validate-error.vue` at line 19, The import of
Message is unused in this component; remove the unused symbol by deleting
Message from the import statement (the import line that currently reads import {
Message } from "@opentiny/vue") in validate-error.vue so the component no longer
imports an unreferenced symbol.

Comment on lines +210 to +229
// 如果配置项有 regexp 校验条件,对每个 tag 单独进行校验
if (regexp) {
const invalidTags = []
for (const tag of tagList) {
// 每个 tag 单独用 regexp 校验
if (regexp.test(tag)) {
newTagUpdateModelValue(prevItem, propItem, tag)
} else {
invalidTags.push(tag)
}
}
// 当有校验不合法的值时,抛出事件
if (invalidTags.length > 0) {
emit('validate-error', {
invalidValues: invalidTags,
field: prevItem.field,
label: prevItem.label,
regexp: regexp.toString()
})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Stateful RegExp.test() bug when regex has g or y flag.

RegExp.prototype.test() is stateful for regexes with the g or y flag — each call advances lastIndex. When iterating tagList with the same regexp, subsequent test() calls may incorrectly fail or pass because lastIndex is not reset between iterations.

This risk is higher in the unlabeled path (lines 263–271), where regexp.test(state.inputValue) is called first during items.find() (line 243), and the same regex object is reused in the per-tag loop — lastIndex carries over.

Consider resetting lastIndex before each test, or using a non-stateful check like regexp.test(tag) with a fresh regex. Since users can supply any regex, the component should be defensive.

🛡️ Proposed fix — reset lastIndex before each test

For the labeled path (lines 210–229):

       if (regexp) {
         const invalidTags = []
         for (const tag of tagList) {
-          // 每个 tag 单独用 regexp 校验
-          if (regexp.test(tag)) {
+          regexp.lastIndex = 0
+          if (regexp.test(tag)) {
             newTagUpdateModelValue(prevItem, propItem, tag)
           } else {
             invalidTags.push(tag)

For the unlabeled path (lines 263–271):

       if (regexp) {
         const invalidTags = []
         for (const tag of tagList) {
-          // 每个 tag 单独用 regexp 校验
-          if (regexp.test(tag)) {
+          regexp.lastIndex = 0
+          if (regexp.test(tag)) {
             updateModelValue(currentItem, {}, label, tag)
           } else {
             invalidTags.push(tag)
🤖 Prompt for AI Agents
In `@packages/search-box/src/composables/use-dropdown.ts` around lines 210 - 229,
The regexp used in the per-tag validation (variable regexp) is stateful when it
has the g or y flags; reset regexp.lastIndex = 0 before each call to
regexp.test() in the tagged path (the loop that iterates tagList and calls
newTagUpdateModelValue(prevItem, propItem, tag)) and also before any other uses
(e.g., the unlabeled path where regexp.test(state.inputValue) is used during
items.find); alternatively construct a fresh RegExp instance for each test (new
RegExp(regexp)) to avoid shared lastIndex, ensuring the emit('validate-error',
{...}) behavior remains unchanged.

Comment on lines +222 to +229
if (invalidTags.length > 0) {
emit('validate-error', {
invalidValues: invalidTags,
field: prevItem.field,
label: prevItem.label,
regexp: regexp.toString()
})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Input not cleared when all tags fail validation.

When every tag in tagList fails regex validation, neither updateModelValue nor newTagUpdateModelValue is called, so resetInput(state) is never triggered. The invalid text remains in the input field after the error event fires. If this is intentional (to let users correct their input), consider documenting it; otherwise, call resetInput(state) after emitting the error.

🤖 Prompt for AI Agents
In `@packages/search-box/src/composables/use-dropdown.ts` around lines 222 - 229,
When all tags fail regex validation the code currently emits the validate-error
with invalidTags but doesn't clear the input because
updateModelValue/newTagUpdateModelValue aren't called; after emitting the error
in the block that checks invalidTags.length > 0 (where emit('validate-error', {
invalidValues: invalidTags, field: prevItem.field, label: prevItem.label,
regexp: regexp.toString() }) is called), invoke resetInput(state) so the input
is cleared when no tag updates occur (ensure this happens only in the path where
tagList validation produced only invalidTags and no
updateModelValue/newTagUpdateModelValue calls were made).

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.

1 participant

Comments