Skip to content

Conversation

@zhaoxiaofeng876
Copy link
Contributor

@zhaoxiaofeng876 zhaoxiaofeng876 commented Jan 5, 2026

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

  • New Features

    • Added TagInput component for managing tag collections with configurable support for tag input/removal, maximum limits, clearing functionality, disabled and readonly states, draggable reordering, collapsed display, custom prefix/suffix slots, separators, and multiple visual variants for PC and mobile-first modes.
  • Documentation

    • Added comprehensive examples and API documentation for TagInput component usage.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Walkthrough

This PR adds a complete TagInput component implementation to the Tiny Vue library, including renderless logic, Vue templates for PC and mobile-first modes, comprehensive type definitions, theme styling, and demonstration examples with documentation.

Changes

Cohort / File(s) Summary
Renderless Logic
packages/renderless/src/tag-input/index.ts, packages/renderless/src/tag-input/vue.ts
Implements tag manipulation handlers (addTag, removeTag, handleBackspace, handleClear) and drag-drop reordering logic; wires reactive state and computed properties for UI management.
Type Definitions
packages/renderless/types/tag-input.type.ts, packages/renderless/types/index.ts
Defines ITagInputState, ITagInputApi, ITagInputProps interfaces; exports renderless type contracts.
Vue Component Implementation
packages/vue/src/tag-input/src/index.ts, packages/vue/src/tag-input/src/pc.vue
Defines TagInput component with 12 props (modelValue, size, tagType, tagEffect, clearable, disabled, max, separator, minCollapsedNum, draggable, placeholder, readonly); PC template renders tag list, input field, tooltips for collapsed tags, and clear icon.
Vue Package Integration
packages/vue/src/tag-input/index.ts, packages/vue/src/tag-input/package.json, packages/vue/index.ts, packages/vue/package.json, packages/modules.json
Adds plugin wrapper with auto-installation; registers component globally; establishes workspace dependency and public exports (TagInput, TinyTagInput).
Theme & Styling
packages/theme/src/index.less, packages/theme/src/tag-input/index.less, packages/theme/src/tag-input/vars.less
Defines LESS variables and styles for tag input container, wrapper, suffix area, disabled states, inner input, and collapsed tag handling.
Demo Components
examples/sites/demos/pc/app/tag-input/basic-usage*.vue, examples/sites/demos/pc/app/tag-input/clearable-tag*.vue, examples/sites/demos/pc/app/tag-input/collapsed-tag*.vue, examples/sites/demos/pc/app/tag-input/disabled-readonly*.vue, examples/sites/demos/pc/app/tag-input/draggable-tag*.vue, examples/sites/demos/pc/app/tag-input/max*.vue, examples/sites/demos/pc/app/tag-input/prefix-suffix*.vue, examples/sites/demos/pc/app/tag-input/separator-tag*.vue
16 Vue example components (8 features × 2 API styles: standard and composition API) demonstrating core features: basic usage, clearable, collapsed tags, disabled/readonly states, drag-and-drop, max constraints, prefix/suffix slots, and separator configuration.
Documentation & Configuration
examples/sites/demos/apis/tag-input.js, examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js, examples/sites/demos/pc/app/tag-input/webdoc/tag-input.*.md, examples/sites/demos/pc/menus.js
API metadata for 12 props and 2 slots; webdoc configuration with 8 demo entries; Chinese/English markdown documentation; menu entry with experimental version tag (3.29.0).

Sequence Diagram

sequenceDiagram
    actor User
    participant Input as TagInput Input
    participant RenderlessLogic as Renderless Handlers
    participant State as Reactive State
    participant UI as Component UI<br/>(TinyTag, TinyTooltip)
    
    User->>Input: Type text + press Enter
    Input->>RenderlessLogic: addTag()
    RenderlessLogic->>State: Validate, split by separator, check max
    State->>State: Append to tagList
    State->>UI: Emit update:modelValue
    UI->>UI: Re-render showTagList & collapsedTagList
    UI->>User: Display new tag
    
    User->>UI: Click tag close icon
    UI->>RenderlessLogic: removeTag(index)
    RenderlessLogic->>State: Remove from tagList
    State->>UI: Emit update:modelValue
    UI->>User: Remove tag from display
    
    User->>Input: Drag tag to new position
    Input->>RenderlessLogic: handleDragStart(index)<br/>handleDragEnter(targetIndex)<br/>handleDrop(index)
    RenderlessLogic->>State: Reorder tagList[draggingIndex]<br/>↔ tagList[targetIndex]
    State->>UI: Emit update:modelValue
    UI->>User: Re-render tags in new order
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • kagol

Poem

🐰 A taggy-tale in code unfolds,
Input fields now catch and hold,
Drag them 'round with graceful ease,
Tags collapsing, features please!
From renderless to styled display,
Input magic comes to stay!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'docs(tag-input): add example' directly reflects the primary changes, which consist of adding documentation and example files for the tag-input component across multiple directories.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings

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: 19

Fix all issues with AI Agents 🤖
In @examples/sites/demos/apis/tag-input.js:
- Line 14: Remove the hidden U+200C zero-width non-joiner from the English
description string so it reads exactly 'Binding Value' (no hidden characters).
Locate the mapping entry with the key 'en-US' and the value currently containing
'‌Binding Value' and replace that value with a clean literal "Binding Value" (or
programmatically strip U+200C, e.g., .replace(/\u200C/g, '') if needed).
- Around line 17-18: The demo references for the TagInput API are wrong: update
the pcDemo and mfDemo values that currently point to 'tag-group-size' to the
TagInput-specific demo slug (e.g. replace 'tag-group-size' with 'basic-usage' or
the TagInput 'model-value' demo ID) so the TagInput API page links to the
correct demo examples.

In @examples/sites/demos/pc/app/tag-input/basic-usage.vue:
- Line 21: Remove the unused maxTagCount variable or bind it to a component:
either delete the maxTagCount declaration if it's not needed, or update one of
the tiny-tag-input usages to pass the value via the :max prop (e.g.,
<tiny-tag-input :max="maxTagCount" ...>) so the variable is actually used.

In @examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue:
- Around line 3-4: The template uses the placeholder variable for the
tiny-tag-input components but placeholder is not defined in the script setup;
add a placeholder definition (e.g., const placeholder = ref('Enter tag') or
const placeholder = 'Enter tag') inside the <script setup> so placeholder is in
scope for the template (ensure it’s exported from the script setup context
alongside data and data1 used by v-model).

In @examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue:
- Line 11: The array `data` is created with reactive([...]) but should use
ref([...]) because v-model may replace the array reference and reactive proxies
can lose reactivity; change the declaration of `data` to use ref([...]) (ensure
`ref` is imported) and update any places that read or mutate the array to use
`data.value` (or keep template v-model usage which works with a ref) so
reactivity is preserved when the component replaces the array reference.

In @examples/sites/demos/pc/app/tag-input/webdoc/tag-input.cn.md:
- Around line 1-7: The TagInput documentation only contains a title and one-line
description; expand tag-input.cn.md to include comprehensive docs: add a "Basic
usage" section with a minimal code example showing <TagInput> usage, an
"API/Props" table listing props (e.g., value, defaultValue, onChange,
placeholder, maxTags, allowDuplicates), an "Events & Methods" section describing
callbacks like onChange and methods (if any), "Examples" showing controlled vs
uncontrolled usage, custom rendering and keyboard interactions, "Common
patterns" (e.g., async suggestions, validation), and an "Accessibility & Notes"
section; ensure examples reference the TagInput component name and include brief
notes on types and expected prop shapes.

In @examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js:
- Around line 59-63: The demo definition for demoId 'clearable-tag' has the
English title incorrectly set to 'basic usage'; update the name object's 'en-US'
value to 'Clearable Tags' so it matches the Chinese 'zh-CN' label and accurately
describes the demo for English users (locate the name property in the demo entry
for demoId 'clearable-tag' and replace the current 'en-US' string).
- Around line 35-39: The demo entry with demoId 'max-tag' has an incorrect
English label; update the name object's 'en-US' value from 'basic usage' to 'Max
Tags' so it matches the Chinese '最大标签数' and the demoId; modify the name property
for the demo with demoId 'max-tag' accordingly.
- Around line 83-87: Update the demo metadata for the demoId 'prefix-suffix' by
changing the English entry in the name object from 'basic usage' to 'Custom
Prefix/Suffix' so the 'en-US' label matches the Chinese label and accurately
describes the demo; locate the name object next to demoId 'prefix-suffix' and
replace the 'en-US' string accordingly.
- Around line 95-99: The English demo name is incorrect: in the demo config
object for demoId 'draggable-tag' (the name property mapping), change the
'en-US' value from 'basic usage' to 'Draggable Tags' so it matches the Chinese
'zh-CN' label and accurately describes the demo.
- Around line 47-51: The English label for the demo entry with demoId
'collapsed-tag' is incorrect: in the name object change the 'en-US' value from
'basic usage' to 'Collapsed Tags' so it matches the Chinese label; update the
name->{'en-US'} string in the demo definition to "Collapsed Tags".
- Around line 71-75: The demo's English title is incorrect: in the object with
demoId 'separator-tag' update the name mapping so name['en-US'] is changed from
'basic usage' to 'Separator Input' (i.e., replace the 'en-US' string value to
match the Chinese label).
- Around line 23-27: Update the demo metadata for demoId 'disabled-readonly' so
the English name under name['en-US'] is corrected from 'basic usage' to
'Disabled and Readonly'; locate the name object next to demoId
'disabled-readonly' in tag-input.js and replace the 'en-US' value accordingly to
match the Chinese label and avoid duplicate names.

In @packages/renderless/src/tag-input/index.ts:
- Around line 99-110: handleDrop can access state.draggingIndex (and
dragTargetIndex) when they are null causing undefined behavior; add a guard at
the start of handleDrop to check that state.draggingIndex and
state.dragTargetIndex are non-null and within bounds of state.tagList (and
return early if not), then proceed with creating newTags, splicing and emitting;
reference the handleDrop function and fields state.draggingIndex,
state.dragTargetIndex, and state.tagList when making the change.
- Around line 80-83: The drag handler is incorrectly calling
event.dataTransfer!.setData with event.target (an EventTarget|null) and using a
non-null assertion on dataTransfer; change this to safely guard dataTransfer and
pass a string: check for event.dataTransfer first, obtain a string identifier
from the element (e.g., cast event.target or event.currentTarget to HTMLElement
and use its id or dataset value), then call
event.dataTransfer.setData('text/plain', identifier) and set
event.dataTransfer.effectAllowed = 'move' without using the non-null assertion;
ensure you handle the case where there is no id/dataset by generating or
skipping the setData call.
- Around line 11-22: The batch-add logic can exceed props.max because newTags
(from value.split when props.separator is set) are pushed wholesale; modify the
code around newTags/tags so you compute available = props.max - tags.length,
then slice newTags to newTags.slice(0, available) before pushing and ensure
state.currentValue is cleared and return if available <= 0; reference symbols:
state.tagList, props.max, props.separator, newTags, tags.push to locate and
update the logic.

In @packages/renderless/src/tag-input/vue.ts:
- Around line 38-41: state.tagList is initialized from props.modelValue once and
won't reflect later parent changes; fix by syncing the prop into the reactive
state: either replace tagList with a computed getter/setter that proxies
props.modelValue (so mutations emit update:modelValue) or add a watch on
props.modelValue that updates state.tagList = newVal || [] (use immediate: true)
and keep emitting update:modelValue in your add/remove handlers; update any
handlers that mutate state.tagList to use the computed setter if you choose the
computed option.

In @packages/renderless/types/tag-input.type.ts:
- Around line 19-31: The modelValue prop is currently declared as a generic
Array but the component and ITagInputState.tagList treat it as an array of
strings; update the prop declaration in the tag-input component
(packages/vue/src/tag-input/src/index.ts) to use a typed PropType<string[]>
(e.g. type: Array as PropType<string[]>) so modelValue, addTag (which calls
value.split(props.separator)), and all tag-list mutations are statically
consistent with string[].

In @packages/theme/src/tag-input/index.less:
- Line 9: Replace the hardcoded border color in the TagInput styles with the
theme CSS variable: locate the rule that sets "border: 1px solid #ccc" (in the
tag input component styles, e.g., the TagInput root selector) and change it to
use a variable like "var(--tv-TagInput-border-color)" with a sensible fallback
(e.g., var(--tv-TagInput-border-color, #ccc)) so theming is respected while
preserving default behavior.
🧹 Nitpick comments (15)
examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue (1)

13-13: Simplify placeholder to a const string.

The placeholder is never mutated, so wrapping it in ref() adds unnecessary reactivity overhead. For consistency with other demos (e.g., max-composition-api.vue uses const placeholder = 'please enter a tag'), use a simple const string instead.

🔎 Proposed fix
-const placeholder = ref('please enter a tag')
+const placeholder = 'please enter a tag'
examples/sites/demos/pc/app/tag-input/draggable-tag-composition-api.vue (1)

1-12: Consider adding placeholder and styling for consistency.

This demo lacks both a placeholder prop and the scoped styling (margin-bottom: 20px) that other tag-input demos include. While this might be intentionally minimal, adding these would maintain consistency across the demo suite and provide a more complete example.

🔎 Proposed additions
 <template>
   <div class="tiny-tag-input-demo">
-    <tiny-tag-input v-model="data" draggable></tiny-tag-input>
+    <tiny-tag-input v-model="data" :placeholder="placeholder" draggable></tiny-tag-input>
   </div>
 </template>
 
 <script setup>
 import { TinyTagInput } from '@opentiny/vue'
 import { reactive } from 'vue'
 
 const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const placeholder = 'please enter a tag'
 </script>
+
+<style scoped>
+.tiny-tag-input-demo .tiny-tag-input {
+  margin-bottom: 20px;
+}
+</style>
packages/vue/src/tag-input/package.json (1)

24-24: Clarify the commented postversion script.

The "//postversion" key uses a JSON comment workaround to disable the postversion script. While this pattern works, it may be confusing to developers unfamiliar with it. Consider either removing the line entirely if the script isn't needed, or adding a comment in nearby documentation explaining why it's disabled.

examples/sites/demos/pc/app/tag-input/prefix-suffix-composition-api.vue (1)

19-19: Simplify placeholder to a const string.

The placeholder is never mutated, so wrapping it in ref() adds unnecessary reactivity overhead. For consistency with other demos (e.g., max-composition-api.vue uses const placeholder = 'please enter a tag'), use a simple const string instead.

🔎 Proposed fix
-const placeholder = ref('please enter a tag')
+const placeholder = 'please enter a tag'
examples/sites/demos/pc/app/tag-input/webdoc/tag-input.en.md (1)

7-7: Consider expanding the documentation.

The description "Used to enter the label" is brief and could be more informative. Consider adding:

  • A more detailed explanation of the component's purpose
  • Key features or use cases
  • A simple usage example
examples/sites/demos/pc/app/tag-input/draggable-tag.vue (1)

1-20: Consider adding styling and placeholder for consistency.

This demo is missing elements present in other TagInput demos:

  1. The scoped <style> section with .tiny-tag-input { margin-bottom: 20px; } (see collapsed-tag.vue, clearable-tag.vue)
  2. The placeholder prop (see other demos)

Adding these would improve visual consistency across the demo gallery.

🔎 Suggested additions for consistency

Add a placeholder to the template:

 <template>
   <div class="tiny-tag-input-demo">
-    <tiny-tag-input v-model="data" draggable></tiny-tag-input>
+    <tiny-tag-input v-model="data" :placeholder="placeholder" draggable></tiny-tag-input>
   </div>
 </template>

Update the data to include placeholder:

   data() {
     return {
-      data: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6']
+      data: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
+      placeholder: 'please enter a tag'
     }
   }

Add the scoped style section:

   }
 }
 </script>
+
+<style scoped>
+.tiny-tag-input-demo .tiny-tag-input {
+  margin-bottom: 20px;
+}
+</style>
examples/sites/demos/pc/app/tag-input/collapsed-tag-composition-api.vue (1)

11-13: Consider simplifying static values for consistency.

The placeholder is wrapped in ref() but appears to be a static string that never changes. For static demo values, consider using a plain const instead to reduce overhead and improve clarity, similar to how it's handled in the Options API variant.

🔎 Optional simplification
 const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
 const minCollapsedNum = ref(5)
-const placeholder = ref('please enter a tag')
+const placeholder = 'please enter a tag'
packages/theme/src/tag-input/index.less (2)

38-48: Consider using CSS variables for fixed dimensions.

The hardcoded values for height (32px), line-height (32px), and font-size (14px) reduce flexibility and theming consistency. While these may be intentional defaults, using CSS variables would allow better customization.

🔎 Proposed refactor
   .@{tag-input-prefix-cls}-inner {
     border: none;
     outline: none;
-    height: 32px;
-    line-height: 32px;
+    height: var(--tv-TagInput-inner-height, 32px);
+    line-height: var(--tv-TagInput-inner-height, 32px);
     color: var(--tv-TagInput-text-color);
     background: var(--tv-TagInput-bg-color);
     padding: 0 var(--tv-TagInput-padding);
-    font-size: 14px;
+    font-size: var(--tv-TagInput-font-size, 14px);
     width: auto;
   }

50-52: Avoid !important if possible.

Using !important can make styles harder to override and maintain. Consider whether the specificity can be increased through selector refinement instead.

packages/vue/src/tag-input/src/index.ts (1)

56-59: Remove redundant default value.

Setting default: undefined is redundant since undefined is already the default value for unspecified properties.

🔎 Proposed fix
   separator: {
-    type: String,
-    default: undefined
+    type: String
   },
examples/sites/demos/apis/tag-input.js (1)

155-156: Missing event documentation.

The component emits update:modelValue on various actions (add tag, remove tag, clear, drag-drop reorder). Consider documenting these events for API completeness, such as:

  • update:modelValue - emitted when the tag list changes
  • Potentially dedicated events for tag-add, tag-remove, clear
packages/vue/src/tag-input/src/pc.vue (2)

18-23: Clarify event handler naming for drag-and-drop.

The @dragend event calls handleDrop, which may cause confusion. Typically dragend fires on the element being dragged when dragging ends, while drop fires on the drop target. Using handleDrop for dragend could mislead maintainers.

Consider renaming to handleDragEnd for clarity, or verify this is intentional behavior.


25-41: Consider keyboard accessibility for collapsed tags tooltip.

The collapsed tags counter (+N) is shown via a tooltip that is activated on hover. Users relying on keyboard navigation may not be able to access or interact with the collapsed tags to remove them.

packages/renderless/src/tag-input/vue.ts (1)

35-36: Unused destructured variables.

ref and parent are destructured but never used in this function. Consider removing them to reduce noise.

🔎 Proposed fix
 export const renderless = (
   props,
-  { reactive, computed, ref }: ISharedRenderlessParamHooks,
-  { emit, parent }: ISharedRenderlessParamUtils<never>
+  { reactive, computed }: ISharedRenderlessParamHooks,
+  { emit }: ISharedRenderlessParamUtils<never>
 ): ITagInputApi => {
packages/renderless/src/tag-input/index.ts (1)

28-33: Unused props parameter.

The props parameter is destructured but never used in removeTag. Same applies to handleBackspace and handleClear.

🔎 Proposed fix
 export const removeTag =
-  ({ emit, props, state }: Pick<ITagInputRenderlessParams, 'emit' | 'props' | 'state'>) =>
+  ({ emit, state }: Pick<ITagInputRenderlessParams, 'emit' | 'state'>) =>
   (index: number) => {

Apply similar changes to handleBackspace (line 36) and handleClear (line 45).

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0084f40 and 73cc76d.

📒 Files selected for processing (36)
  • examples/sites/demos/apis/tag-input.js
  • examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/basic-usage.vue
  • examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/clearable-tag.vue
  • examples/sites/demos/pc/app/tag-input/collapsed-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/collapsed-tag.vue
  • examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/disabled-readonly.vue
  • examples/sites/demos/pc/app/tag-input/draggable-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/draggable-tag.spec.ts
  • examples/sites/demos/pc/app/tag-input/draggable-tag.vue
  • examples/sites/demos/pc/app/tag-input/max-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/max.vue
  • examples/sites/demos/pc/app/tag-input/prefix-suffix-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/prefix-suffix.vue
  • examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/separator-tag.vue
  • examples/sites/demos/pc/app/tag-input/webdoc/tag-input.cn.md
  • examples/sites/demos/pc/app/tag-input/webdoc/tag-input.en.md
  • examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js
  • examples/sites/demos/pc/menus.js
  • packages/modules.json
  • packages/renderless/src/tag-input/index.ts
  • packages/renderless/src/tag-input/vue.ts
  • packages/renderless/types/index.ts
  • packages/renderless/types/tag-input.type.ts
  • packages/theme/src/index.less
  • packages/theme/src/tag-input/index.less
  • packages/theme/src/tag-input/vars.less
  • packages/vue/index.ts
  • packages/vue/package.json
  • packages/vue/src/tag-input/index.ts
  • packages/vue/src/tag-input/package.json
  • packages/vue/src/tag-input/src/index.ts
  • packages/vue/src/tag-input/src/pc.vue
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-04T09:35:13.159Z
Learnt from: zzcr
Repo: opentiny/tiny-vue PR: 2481
File: packages/theme/src/time-range/vars.less:27-28
Timestamp: 2024-11-04T09:35:13.159Z
Learning: 在 `packages/theme/src/time-range/vars.less` 文件中,应使用 `var(--tv-TimeRange-header-height)` 作为 `--tv-TimeRange-header-line-height` 的值,以保持一致性。

Applied to files:

  • packages/theme/src/tag-input/vars.less
🧬 Code graph analysis (4)
packages/vue/src/tag-input/src/index.ts (1)
packages/vue-common/src/index.ts (4)
  • $props (45-53)
  • $prefix (43-43)
  • props (55-73)
  • $setup (199-233)
packages/vue/src/tag-input/index.ts (1)
packages/vue/index.ts (3)
  • TagInput (754-754)
  • TagInput (755-755)
  • version (421-421)
packages/renderless/types/tag-input.type.ts (2)
packages/vue/src/tag-input/src/index.ts (1)
  • tagInputProps (15-68)
packages/vue-hooks/types/shared.type.ts (1)
  • ISharedRenderlessFunctionParams (1-15)
packages/renderless/src/tag-input/index.ts (2)
packages/renderless/types/tag-input.type.ts (1)
  • ITagInputRenderlessParams (51-55)
packages/vue-common/src/index.ts (1)
  • props (55-73)
🔇 Additional comments (20)
examples/sites/demos/pc/app/tag-input/max-composition-api.vue (1)

1-20: LGTM!

The demo correctly demonstrates the max tag limit functionality. The data array intentionally contains 6 tags while max is set to 5, effectively showcasing the limiting behavior. The use of const for static values (max and placeholder) is appropriate.

packages/vue/src/tag-input/index.ts (1)

1-30: LGTM! Standard Vue plugin implementation.

The plugin wrapper follows the library's established patterns for component registration, versioning, and auto-installation. The code is clean and correctly structured.

packages/renderless/types/index.ts (1)

183-183: LGTM! Export correctly placed.

The new export statement for tag-input types is correctly positioned in alphabetical order and follows the established pattern.

packages/theme/src/index.less (1)

137-137: LGTM! Import correctly placed.

The tag-input theme import is correctly positioned in alphabetical order and follows the established pattern for component theme imports.

examples/sites/demos/pc/app/tag-input/collapsed-tag.vue (1)

1-28: LGTM! Well-structured demo component.

The collapsed tag demo correctly demonstrates the minCollapsedNum prop with clear, simple code. The structure follows Vue best practices for Options API components.

examples/sites/demos/pc/app/tag-input/clearable-tag.vue (1)

1-27: LGTM! Clear demonstration of the clearable feature.

The clearable tag demo is well-implemented and consistent with the other demo files in structure and style.

examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue (1)

1-10: LGTM for template, imports, and primitive refs.

The template structure, imports, and use of ref() for primitive values (placeholder, separator) are correct. The scoped styling is appropriate for the demo.

Also applies to: 12-20

examples/sites/demos/pc/menus.js (1)

178-178: LGTM! TagInput menu entry properly configured.

The menu entry is correctly positioned in the Form components section with appropriate metadata marking it as experimental in version 3.29.0. The structure is consistent with other component entries.

examples/sites/demos/pc/app/tag-input/prefix-suffix.vue (1)

1-34: LGTM! Clean demo of prefix and suffix slots.

The demo effectively demonstrates the slot functionality of the TagInput component with clear, straightforward code. The template structure, component registration, and styling all follow Vue best practices.

examples/sites/demos/pc/app/tag-input/separator-tag.vue (1)

1-28: LGTM! Clear demonstration of the separator prop.

The demo concisely shows how to configure a custom separator for tag input. The implementation is clean and follows the established demo patterns in the project.

examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue (1)

1-23: LGTM! Excellent composition API demonstration.

The demo effectively showcases multiple TagInput configurations using Vue 3's composition API. The use of reactive for arrays and ref for the placeholder is correct, and the three variants (default, info/light, success/plain) provide good visual examples for users.

packages/vue/package.json (1)

200-200: LGTM! Dependency correctly added.

The workspace dependency for @opentiny/vue-tag-input is properly added in alphabetical order and follows the established pattern for component dependencies in the monorepo.

packages/theme/src/tag-input/vars.less (1)

13-41: LGTM! Well-structured theme variables.

The CSS custom properties are well-organized with clear sectioning, consistent naming conventions, and appropriate fallback values. The usage of var() with fallbacks aligns with the codebase's theming patterns.

examples/sites/demos/pc/app/tag-input/disabled-readonly.vue (1)

8-23: LGTM! Clean Options API implementation.

The component correctly defines all referenced properties and follows Vue Options API best practices. The structure is clear and the data initialization is appropriate for demonstrating disabled and readonly states.

examples/sites/demos/pc/app/tag-input/max.vue (1)

16-17: This is intentional behavior. The max prop controls whether users can add new tags, not the initial data size. Both the Options API and Composition API demo variants (max.vue and max-composition-api.vue) deliberately initialize with 6 tags while setting max: 5, demonstrating that the component accepts initial data exceeding the limit and only prevents new additions once the max is reached.

examples/sites/demos/pc/app/tag-input/basic-usage.vue (1)

1-32: LGTM!

The demo effectively showcases three different TagInput configurations with varying tag types and effects. The component usage and styling are appropriate.

packages/vue/index.ts (1)

166-166: LGTM!

The TagInput component integration follows the established pattern consistently across all export locations (import, components array, named exports, and default export). The alphabetical ordering is maintained correctly.

Also applies to: 368-368, 754-755, 1155-1156

packages/vue/src/tag-input/src/index.ts (1)

15-76: LGTM!

The component definition follows the standard TinyVue pattern correctly. The prop definitions include appropriate types, defaults, and validators. The setup function properly delegates to $setup with the required parameters.

packages/modules.json (1)

2197-2215: LGTM!

The TagInput module entries follow the established patterns for other components in this file. The component entry correctly defines both mobile-first and pc modes, and the template entries reference the appropriate Vue files.

packages/vue/src/tag-input/src/pc.vue (1)

63-96: LGTM!

The component setup follows the established renderless pattern used in this codebase. Props are properly declared and the component integrates correctly with the theme and sub-components.

defaultValue: '[]',
desc: {
'zh-CN': '绑定值',
'en-US': '‌Binding 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 | 🟡 Minor

Hidden zero-width character in English description.

The English description contains a zero-width non-joiner character (U+200C) before "Binding Value". This invisible character may cause display or search issues.

🔎 Proposed fix
-          'en-US': '‌Binding Value'
+          'en-US': 'Binding 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
'en-US': '‌Binding Value'
'en-US': 'Binding Value'
🤖 Prompt for AI Agents
In @examples/sites/demos/apis/tag-input.js around line 14, Remove the hidden
U+200C zero-width non-joiner from the English description string so it reads
exactly 'Binding Value' (no hidden characters). Locate the mapping entry with
the key 'en-US' and the value currently containing '‌Binding Value' and replace
that value with a clean literal "Binding Value" (or programmatically strip
U+200C, e.g., .replace(/\u200C/g, '') if needed).

Comment on lines +17 to +18
pcDemo: 'tag-group-size',
mfDemo: 'tag-group-size'
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

Incorrect demo references.

The demo references tag-group-size which appears to be from a different component (TagGroup). For the TagInput component, the model-value prop should reference TagInput-specific demos like basic-usage.

🔎 Proposed fix
-          pcDemo: 'tag-group-size',
-          mfDemo: 'tag-group-size'
+          pcDemo: 'basic-usage',
+          mfDemo: 'basic-usage'
📝 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
pcDemo: 'tag-group-size',
mfDemo: 'tag-group-size'
pcDemo: 'basic-usage',
mfDemo: 'basic-usage'
🤖 Prompt for AI Agents
In @examples/sites/demos/apis/tag-input.js around lines 17-18, The demo
references for the TagInput API are wrong: update the pcDemo and mfDemo values
that currently point to 'tag-group-size' to the TagInput-specific demo slug
(e.g. replace 'tag-group-size' with 'basic-usage' or the TagInput 'model-value'
demo ID) so the TagInput API page links to the correct demo examples.

data: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
data1: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
data2: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
maxTagCount: 3,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused variable.

The maxTagCount variable is declared but never used in the template. Consider removing it or binding it to one of the tiny-tag-input components with the :max prop.

🔎 Proposed fix
       data: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
       data1: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
       data2: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
-      maxTagCount: 3,
       placeholder: 'please enter a tag'

Or if you intend to demonstrate the max prop, bind it to one of the inputs:

-    <tiny-tag-input v-model="data" :placeholder="placeholder"></tiny-tag-input>
+    <tiny-tag-input v-model="data" :placeholder="placeholder" :max="maxTagCount"></tiny-tag-input>
📝 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
maxTagCount: 3,
data: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
data1: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
data2: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'],
placeholder: 'please enter a tag'
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/basic-usage.vue around line 21, Remove
the unused maxTagCount variable or bind it to a component: either delete the
maxTagCount declaration if it's not needed, or update one of the tiny-tag-input
usages to pass the value via the :max prop (e.g., <tiny-tag-input
:max="maxTagCount" ...>) so the variable is actually used.

Comment on lines +3 to +4
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing placeholder definition causes runtime error.

The template references placeholder on lines 3-4, but it's not defined in the script setup section. This will cause a ReferenceError at runtime.

🔎 Proposed fix
 const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
 const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const placeholder = 'please enter a tag'
📝 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
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const placeholder = 'please enter a tag'
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
around lines 3-4, The template uses the placeholder variable for the
tiny-tag-input components but placeholder is not defined in the script setup;
add a placeholder definition (e.g., const placeholder = ref('Enter tag') or
const placeholder = 'Enter tag') inside the <script setup> so placeholder is in
scope for the template (ensure it’s exported from the script setup context
alongside data and data1 used by v-model).

import { TinyTagInput } from '@opentiny/vue'
import { reactive, ref } from 'vue'

const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
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

Use ref() instead of reactive() for arrays bound to v-model.

When an array is bound to v-model, the component may replace the entire array reference. Using reactive() creates a proxy that can lose reactivity when the reference is replaced. The Vue 3 best practice is to use ref() for arrays in Composition API, especially with v-model bindings.

🔎 Recommended fix
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
📝 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 data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue
around line 11, The array `data` is created with reactive([...]) but should use
ref([...]) because v-model may replace the array reference and reactive proxies
can lose reactivity; change the declaration of `data` to use ref([...]) (ensure
`ref` is imported) and update any places that read or mutate the array to use
`data.value` (or keep template v-model usage which works with a ref) so
reactivity is preserved when the component replaces the array reference.

Comment on lines +80 to +83
if (event.target) {
event.dataTransfer?.setData('text/plain', event.target)
event.dataTransfer!.effectAllowed = 'move'
}
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

Incorrect usage of setData and potential null reference.

setData expects a string as the second argument, but event.target is an EventTarget | null. Additionally, the non-null assertion on dataTransfer could throw if dataTransfer is undefined (e.g., in non-drag contexts).

🔎 Proposed fix
   (index: number, event: DragEvent) => {
     state.draggingIndex = index
-    if (event.target) {
-      event.dataTransfer?.setData('text/plain', event.target)
-      event.dataTransfer!.effectAllowed = 'move'
+    if (event.dataTransfer) {
+      event.dataTransfer.setData('text/plain', String(index))
+      event.dataTransfer.effectAllowed = 'move'
     }
   }
📝 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 (event.target) {
event.dataTransfer?.setData('text/plain', event.target)
event.dataTransfer!.effectAllowed = 'move'
}
if (event.dataTransfer) {
event.dataTransfer.setData('text/plain', String(index))
event.dataTransfer.effectAllowed = 'move'
}
🤖 Prompt for AI Agents
In @packages/renderless/src/tag-input/index.ts around lines 80-83, The drag
handler is incorrectly calling event.dataTransfer!.setData with event.target (an
EventTarget|null) and using a non-null assertion on dataTransfer; change this to
safely guard dataTransfer and pass a string: check for event.dataTransfer first,
obtain a string identifier from the element (e.g., cast event.target or
event.currentTarget to HTMLElement and use its id or dataset value), then call
event.dataTransfer.setData('text/plain', identifier) and set
event.dataTransfer.effectAllowed = 'move' without using the non-null assertion;
ensure you handle the case where there is no id/dataset by generating or
skipping the setData call.

Comment on lines +99 to +110
export const handleDrop =
({ emit, props, state }: Pick<ITagInputRenderlessParams, 'emit' | 'props' | 'state'>) =>
(index: number, event: DragEvent) => {
event.preventDefault()
const newTags = [...(state.tagList ?? [])]
const draggingTag = newTags[state.draggingIndex]
newTags.splice(state.draggingIndex, 1)
newTags.splice(state.dragTargetIndex, 0, draggingTag)
state.draggingIndex = null
state.dragTargetIndex = null
state.tagList = newTags
emit('update:modelValue', newTags)
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

Potential null reference when accessing draggingIndex.

state.draggingIndex is typed as null initially and could still be null when handleDrop executes. Accessing newTags[state.draggingIndex] where draggingIndex is null will result in undefined, and the subsequent splice operations will produce incorrect behavior.

🔎 Proposed fix
 export const handleDrop =
   ({ emit, props, state }: Pick<ITagInputRenderlessParams, 'emit' | 'props' | 'state'>) =>
   (index: number, event: DragEvent) => {
     event.preventDefault()
+    if (state.draggingIndex === null || state.dragTargetIndex === null) {
+      return
+    }
     const newTags = [...(state.tagList ?? [])]
     const draggingTag = newTags[state.draggingIndex]
     newTags.splice(state.draggingIndex, 1)
     newTags.splice(state.dragTargetIndex, 0, draggingTag)
     state.draggingIndex = null
     state.dragTargetIndex = null
     state.tagList = newTags
     emit('update:modelValue', newTags)
   }
📝 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
export const handleDrop =
({ emit, props, state }: Pick<ITagInputRenderlessParams, 'emit' | 'props' | 'state'>) =>
(index: number, event: DragEvent) => {
event.preventDefault()
const newTags = [...(state.tagList ?? [])]
const draggingTag = newTags[state.draggingIndex]
newTags.splice(state.draggingIndex, 1)
newTags.splice(state.dragTargetIndex, 0, draggingTag)
state.draggingIndex = null
state.dragTargetIndex = null
state.tagList = newTags
emit('update:modelValue', newTags)
export const handleDrop =
({ emit, props, state }: Pick<ITagInputRenderlessParams, 'emit' | 'props' | 'state'>) =>
(index: number, event: DragEvent) => {
event.preventDefault()
if (state.draggingIndex === null || state.dragTargetIndex === null) {
return
}
const newTags = [...(state.tagList ?? [])]
const draggingTag = newTags[state.draggingIndex]
newTags.splice(state.draggingIndex, 1)
newTags.splice(state.dragTargetIndex, 0, draggingTag)
state.draggingIndex = null
state.dragTargetIndex = null
state.tagList = newTags
emit('update:modelValue', newTags)
}
🤖 Prompt for AI Agents
In @packages/renderless/src/tag-input/index.ts around lines 99-110, handleDrop
can access state.draggingIndex (and dragTargetIndex) when they are null causing
undefined behavior; add a guard at the start of handleDrop to check that
state.draggingIndex and state.dragTargetIndex are non-null and within bounds of
state.tagList (and return early if not), then proceed with creating newTags,
splicing and emitting; reference the handleDrop function and fields
state.draggingIndex, state.dragTargetIndex, and state.tagList when making the
change.

Comment on lines +38 to +41
const state: ITagInputState = reactive({
currentValue: '',
tagList: props.modelValue || [],
disabled: computed(() => props.disabled),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: tagList is not reactive to prop changes.

tagList is initialized from props.modelValue once during setup, but it won't update if the parent component changes modelValue externally. This breaks the expected v-model behavior where parent-driven updates should reflect in the component.

The component mutates state.tagList directly and emits update:modelValue, but if the parent changes modelValue independently (e.g., programmatic reset), the internal state will be stale.

🔎 Proposed fix - use computed or watch

Option 1: Make tagList a computed with getter/setter:

   const state: ITagInputState = reactive({
     currentValue: '',
-    tagList: props.modelValue || [],
+    tagList: computed({
+      get: () => props.modelValue || [],
+      set: (val) => emit('update:modelValue', val)
+    }),

Option 2: Add a watch to sync prop changes (simpler but maintains current pattern):

watch(() => props.modelValue, (newVal) => {
  state.tagList = newVal || []
}, { immediate: true })

Note: If using Option 1, handler functions would need adjustment since they currently mutate state.tagList directly.

🤖 Prompt for AI Agents
In @packages/renderless/src/tag-input/vue.ts around lines 38-41, state.tagList
is initialized from props.modelValue once and won't reflect later parent
changes; fix by syncing the prop into the reactive state: either replace tagList
with a computed getter/setter that proxies props.modelValue (so mutations emit
update:modelValue) or add a watch on props.modelValue that updates state.tagList
= newVal || [] (use immediate: true) and keep emitting update:modelValue in your
add/remove handlers; update any handlers that mutate state.tagList to use the
computed setter if you choose the computed option.

Comment on lines +19 to +31
export interface ITagInputState {
currentValue: string
tagList: string[]
disabled: boolean
closeable: boolean
showClearIcon: boolean
showTagList: string[]
collapsedTagList: string[]
isHovering: boolean
isFocused: boolean
draggingIndex: null | number
dragTargetIndex: null | number
}
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find modelValue prop definition and tagList usage
rg -n --type=ts "modelValue|tagList" packages/renderless/src/tag-input/ packages/vue/src/tag-input/ -A3 -B3 | head -200

Repository: opentiny/tiny-vue

Length of output: 6491


🏁 Script executed:

#!/bin/bash
# Check the props interface/definition for modelValue type
fd . packages/renderless/types/ packages/vue/src/tag-input/ --name "*.ts" --type f | xargs rg -l "modelValue"

Repository: opentiny/tiny-vue

Length of output: 22789


🏁 Script executed:

#!/bin/bash
# Search for TagInput component definition and props
rg -n "interface.*TagInput|type.*TagInput" packages/renderless/types/ packages/vue/src/tag-input/ -A10 | head -150

Repository: opentiny/tiny-vue

Length of output: 2429


🏁 Script executed:

#!/bin/bash
# Search for tag-input tests and documentation
find . -path "*/tag-input*test*" -o -path "*/tag-input*spec*" 2>/dev/null | head -10

Repository: opentiny/tiny-vue

Length of output: 122


🏁 Script executed:

#!/bin/bash
# Look for any type definitions or documentation about tag-input props
rg -n "tagInputProps|ITagInputProps" packages/renderless/types/ -A20 | head -100

Repository: opentiny/tiny-vue

Length of output: 2057


🏁 Script executed:

#!/bin/bash
# Check if there's a prop type definition file
find packages -name "*prop*" -path "*tag-input*" -type f

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

#!/bin/bash
# Find and examine the tagInputProps definition
cat packages/vue/src/tag-input/src/index.ts

Repository: opentiny/tiny-vue

Length of output: 1823


🏁 Script executed:

#!/bin/bash
# Check if there are any validation or type guard mechanisms for the modelValue
rg -n "modelValue|Array<|string\[\]" packages/renderless/src/tag-input/index.ts -A2 -B2 | head -50

Repository: opentiny/tiny-vue

Length of output: 709


Update modelValue prop type to be explicit about string elements.

The modelValue prop is typed as generic Array but the implementation treats it exclusively as an array of strings. The addTag function uses value.split(props.separator), and all state mutations directly manipulate string arrays. Update the prop definition in packages/vue/src/tag-input/src/index.ts to type: Array as PropType<string[]> to ensure type consistency with the ITagInputState.tagList: string[] interface and accurately reflect the component's constraint.

🤖 Prompt for AI Agents
In @packages/renderless/types/tag-input.type.ts around lines 19-31, The
modelValue prop is currently declared as a generic Array but the component and
ITagInputState.tagList treat it as an array of strings; update the prop
declaration in the tag-input component (packages/vue/src/tag-input/src/index.ts)
to use a typed PropType<string[]> (e.g. type: Array as PropType<string[]>) so
modelValue, addTag (which calls value.split(props.separator)), and all tag-list
mutations are statically consistent with string[].


.@{tag-input-prefix-cls} {
.inject-TagInput-vars();
border: 1px solid #ccc;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use CSS variable for border color.

The hardcoded border color #ccc breaks theming consistency. Consider using a CSS variable like var(--tv-TagInput-border-color) to match the theming pattern used elsewhere in this file.

🔎 Proposed fix
-  border: 1px solid #ccc;
+  border: 1px solid var(--tv-TagInput-border-color);
📝 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
border: 1px solid #ccc;
border: 1px solid var(--tv-TagInput-border-color);
🤖 Prompt for AI Agents
In @packages/theme/src/tag-input/index.less around line 9, Replace the hardcoded
border color in the TagInput styles with the theme CSS variable: locate the rule
that sets "border: 1px solid #ccc" (in the tag input component styles, e.g., the
TagInput root selector) and change it to use a variable like
"var(--tv-TagInput-border-color)" with a sensible fallback (e.g.,
var(--tv-TagInput-border-color, #ccc)) so theming is respected while preserving
default behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant