Skip to content

feat(PinInput): add delimiter option#6392

Open
al1maher wants to merge 2 commits intonuxt:v4from
al1maher:feat/allow-delimiter-for-pin-input
Open

feat(PinInput): add delimiter option#6392
al1maher wants to merge 2 commits intonuxt:v4from
al1maher:feat/allow-delimiter-for-pin-input

Conversation

@al1maher
Copy link
Copy Markdown
Contributor

Allow splitting up input to improve readability or consistency - depending on how a brand prefers to present the code.

🔗 Linked issue

Resolves #6389

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@al1maher al1maher requested a review from benjamincanac as a code owner April 23, 2026 15:30
@github-actions github-actions Bot added the v4 #4488 label Apr 23, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

Adds a delimiter feature to the PinInput component. Introduces an optional delimiterPositions?: number[] prop and a delimiter named slot; the template was restructured to render inputs in a template v-for and conditionally insert delimiter markup after specified indices with a default bullet fallback. Documentation is updated with a Delimiter guide and slot usage examples, and the playground demo adds a 6-character PIN example with a delimiter at position 3.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses issue #6389 by implementing delimiter positioning and rendering, but does not fully implement the comprehensive requirements like sanitizing delimiters from input values or handling paste/autofill edge cases. Implement input sanitization to strip delimiters from stored values, and add handling for paste and autofill scenarios to ensure only intended characters are stored.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description relates to the changeset by explaining the purpose (improving readability through input splitting) and references the linked issue #6389, though it lacks detailed implementation specifics.
Out of Scope Changes check ✅ Passed All code changes are in-scope: adding the delimiterPositions prop, rendering delimiter slots, updating documentation, and adding playground examples all directly support the delimiter feature objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The PR title 'feat(PinInput): add delimiter option' accurately summarizes the main change—introducing a new delimiter feature to the PinInput component. It is concise, clear, and directly reflects the primary objective of the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
Contributor

@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: 2

🧹 Nitpick comments (1)
src/runtime/components/PinInput.vue (1)

152-156: Consider exposing delimiter styling through the theme ui slots.

The hardcoded <span class="text-dimmed">•</span> and wrapper <span> aren't themeable via ui.delimiter like the rest of the component (e.g., ui.base, ui.root). For consistency with other components and to let users override spacing/color without resorting to the slot, consider adding a delimiter slot entry to the theme and applying ui.delimiter({ class: uiProp?.delimiter }) here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/PinInput.vue` around lines 152 - 156, The delimiter
markup in PinInput.vue currently uses a hardcoded <span
class="text-dimmed">•</span>; change this to use the theme `ui.delimiter` slot
so users can style it: when rendering the delimiter (where
`delimiterPositions?.includes((index as number) + 1)`), apply the theme helper
like `ui.delimiter({ class: uiProp?.delimiter })` to the wrapper/element instead
of the fixed "text-dimmed" class and keep the named slot `delimiter` as
fallback; also add a corresponding `ui.delimiter` entry to the theme config so
consumers can override spacing/color consistently with `ui.base`/`ui.root`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/content/docs/2.components/pin-input.md`:
- Line 173: The "Delimiter" heading is for a new feature and needs the Soon
badge; update the heading "### Delimiter" to include the badge token
:badge{label="Soon" class="align-text-top"} immediately after the heading text
so it reads like the other new-feature headings in this doc (ensure you modify
the heading line that contains "### Delimiter").

In `@src/runtime/components/PinInput.vue`:
- Around line 152-156: The delimiter check in PinInput.vue uses
delimiterPositions?.includes((index as number) + 1) which can match a position
equal to length and render a trailing delimiter; update the condition to also
ensure the computed position is less than the total length (e.g., only render
when (index + 1) < length and delimiterPositions includes that position). Modify
the span's v-if to combine the includes check with a guard against positions >=
length so delimiters are only inserted between inputs (referencing
delimiterPositions, index, and length in the PinInput component).

---

Nitpick comments:
In `@src/runtime/components/PinInput.vue`:
- Around line 152-156: The delimiter markup in PinInput.vue currently uses a
hardcoded <span class="text-dimmed">•</span>; change this to use the theme
`ui.delimiter` slot so users can style it: when rendering the delimiter (where
`delimiterPositions?.includes((index as number) + 1)`), apply the theme helper
like `ui.delimiter({ class: uiProp?.delimiter })` to the wrapper/element instead
of the fixed "text-dimmed" class and keep the named slot `delimiter` as
fallback; also add a corresponding `ui.delimiter` entry to the theme config so
consumers can override spacing/color consistently with `ui.base`/`ui.root`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc64eb2f-181d-46f7-9495-08a6538a6d46

📥 Commits

Reviewing files that changed from the base of the PR and between 969c2ca and 15df058.

⛔ Files ignored due to path filters (2)
  • test/components/__snapshots__/PinInput-vue.spec.ts.snap is excluded by !**/*.snap
  • test/components/__snapshots__/PinInput.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • docs/content/docs/2.components/pin-input.md
  • playgrounds/nuxt/app/pages/components/pin-input.vue
  • src/runtime/components/PinInput.vue

Comment thread docs/content/docs/2.components/pin-input.md Outdated
Comment thread src/runtime/components/PinInput.vue Outdated
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 23, 2026

npm i https://pkg.pr.new/@nuxt/ui@6392

commit: d5d521a

@al1maher al1maher changed the title feat(pin-input): add delimiter option to seperate inputs at sepecific points feat(pin-input): add delimiter option Apr 24, 2026
@al1maher al1maher changed the title feat(pin-input): add delimiter option feat(PinInput): add delimiter option Apr 24, 2026
Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (2)
src/runtime/components/PinInput.vue (1)

118-120: Trailing-delimiter guard looks good; drop redundant as number casts.

The (index as number) + 1 < looseToNumber(props.length) guard correctly prevents a dangling delimiter after the last input. Minor nit: since index is already typed as number in the function signature, both index as number casts are no-ops and can be simplified.

♻️ Proposed simplification
 function shouldInsertDelimiter(index: number) {
-  return props.delimiterPositions?.includes((index as number) + 1) && (index as number) + 1 < looseToNumber(props.length)
+  return props.delimiterPositions?.includes(index + 1) && index + 1 < looseToNumber(props.length)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/PinInput.vue` around lines 118 - 120, The function
shouldInsertDelimiter currently contains redundant "as number" casts on the
already-typed parameter index; simplify by removing those casts and use index +
1 directly in both places while keeping the existing logic and guards
(props.delimiterPositions?.includes(index + 1) && index + 1 <
looseToNumber(props.length)); update references to props.delimiterPositions and
props.length only (no other logic changes).
docs/content/docs/2.components/pin-input.md (1)

211-215: Verify the blank line under delimiter: | doesn't leak into the rendered slot.

The literal block scalar preserves the empty line between | and <span …>, which may render as a leading empty text node inside the delimiter slot (and potentially a stray line break in the demo). If the playground component-code loader trims it, this is fine — otherwise remove the blank line.

♻️ Proposed tidy-up
 slots:
   delimiter: |
-
     <span class="text-primary font-bold">-</span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/docs/2.components/pin-input.md` around lines 211 - 215, The
literal block under the YAML frontmatter for the delimiter slot contains an
extra blank line after "delimiter: |" which can produce an unwanted leading
empty text node; remove that blank line so the content starts immediately after
"delimiter: |" (i.e., ensure the slot's literal block begins with "<span
class=\"text-primary font-bold\">-</span>" on the next line) to prevent a stray
empty node in the delimiter slot rendering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/runtime/components/PinInput.vue`:
- Around line 42-46: The component's paste/autofill isn't sanitizing delimiter
characters so pasted text like "123-456" can populate delimiter slots; add
normalization that strips any characters at delimiterPositions boundaries before
distributing into inputs: implement an onPaste handler on the root/input
elements that reads clipboard data, removes characters at indices corresponding
to delimiterPositions (or strips known delimiter chars), and then emits the
cleaned value via update:model-value (or calls the existing value-distribution
logic); also apply the same normalization to any external updates handled by the
update:model-value path so programmatic Autofill/paste-like updates are
normalized; reference PinInput.vue props/methods: delimiterPositions,
update:model-value event, and the input distribution logic to locate where to
integrate the sanitization.

---

Nitpick comments:
In `@docs/content/docs/2.components/pin-input.md`:
- Around line 211-215: The literal block under the YAML frontmatter for the
delimiter slot contains an extra blank line after "delimiter: |" which can
produce an unwanted leading empty text node; remove that blank line so the
content starts immediately after "delimiter: |" (i.e., ensure the slot's literal
block begins with "<span class=\"text-primary font-bold\">-</span>" on the next
line) to prevent a stray empty node in the delimiter slot rendering.

In `@src/runtime/components/PinInput.vue`:
- Around line 118-120: The function shouldInsertDelimiter currently contains
redundant "as number" casts on the already-typed parameter index; simplify by
removing those casts and use index + 1 directly in both places while keeping the
existing logic and guards (props.delimiterPositions?.includes(index + 1) &&
index + 1 < looseToNumber(props.length)); update references to
props.delimiterPositions and props.length only (no other logic changes).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a7f4c71d-731c-4320-99bf-0aa111fef563

📥 Commits

Reviewing files that changed from the base of the PR and between 15df058 and d5d521a.

📒 Files selected for processing (2)
  • docs/content/docs/2.components/pin-input.md
  • src/runtime/components/PinInput.vue

Comment on lines +42 to +46
/**
* Position(s) after which to insert a delimiter.
* @example [3, 6] // Insert delimiters after 3rd and 6th inputs
*/
delimiterPositions?: number[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider paste/autofill sanitization to fully address issue #6389.

The linked issue calls out robust paste/autofill handling — e.g., pasting "123-456" or "123 456" into a PIN that displays delimiters at position 3 should strip the delimiter characters and fill ["1","2","3","4","5","6"]. The current implementation is display-only (delimiter is a sibling <span>, so it never enters the inputs), which means:

  • With type="number", reka-ui already filters non-numeric input on paste — fine.
  • With type="text", a paste of "123-456" will distribute - into the 4th slot rather than being treated as a delimiter and skipped.

If that's intentionally out of scope for this PR, consider calling it out as a known limitation in the docs; otherwise, an @paste/update:model-value normalization step that strips characters appearing at delimiterPositions boundaries would close the gap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/components/PinInput.vue` around lines 42 - 46, The component's
paste/autofill isn't sanitizing delimiter characters so pasted text like
"123-456" can populate delimiter slots; add normalization that strips any
characters at delimiterPositions boundaries before distributing into inputs:
implement an onPaste handler on the root/input elements that reads clipboard
data, removes characters at indices corresponding to delimiterPositions (or
strips known delimiter chars), and then emits the cleaned value via
update:model-value (or calls the existing value-distribution logic); also apply
the same normalization to any external updates handled by the update:model-value
path so programmatic Autofill/paste-like updates are normalized; reference
PinInput.vue props/methods: delimiterPositions, update:model-value event, and
the input distribution logic to locate where to integrate the sanitization.

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

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PinInput: Allow split / delimiter for readability

1 participant