Skip to content

Comments

feat: add input component#1173

Merged
danielroe merged 16 commits intonpmx-dev:mainfrom
alexdln:feat/add-input-component
Feb 8, 2026
Merged

feat: add input component#1173
danielroe merged 16 commits intonpmx-dev:mainfrom
alexdln:feat/add-input-component

Conversation

@alexdln
Copy link
Member

@alexdln alexdln commented Feb 7, 2026

Added a common component for text-like inputs and used it throughout the site. The current search-field is used as a basis, with soft rounding, a light border, a bright border on hover, an accent border on focus, and an accent outline 2px from the input on focus

I went through all the places and made additional adjustments where needed. Where I could, I increased the size a bit (to 32px instead of 28.6). Also, if it was a group with a button or block, I adjusted the size for them as well.

I made the inputs a consistent height to avoid having to play exact matches in the future. Generally, leading-none with padding covered this issue, but sometimes it would break, so I explicitly specified the height as well.

(logic is covered for 100%, so I hope I configured everything correctly)

Closes #1172

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

📝 Walkthrough

Walkthrough

Adds a new InputBase Vue component (props: disabled, size, noCorrect; emits: focus, blur; exposes focus() and blur()). Replaces numerous native input elements across the app with InputBase (header, search, auth/connector modals, compare UI, org panels, package controls, date inputs, OTP input), standardising classes and sizes. Adjusts AppHeader centre alignment to use justify-end on the home page and justify-center elsewhere while preserving the existing search-expanded visibility condition. Adds unit and accessibility tests for InputBase. No existing exported public signatures were removed.

Possibly related PRs

Suggested reviewers

  • danielroe
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description accurately describes the implementation of a reusable input component and its application throughout the codebase.
Linked Issues check ✅ Passed The pull request fully implements all stated objectives from issue #1172: creates InputBase component with specified styling, replaces text inputs site-wide, and achieves 100% test coverage.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the input component consolidation objective; no unrelated modifications detected.

✏️ 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

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

Copy link
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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/Filter/Panel.vue (1)

116-119: ⚠️ Potential issue | 🟡 Minor

Switch from @input and :value to @update:modelValue and :model-value with InputBase.

InputBase defines only update:modelValue (plus focus and blur events), not native input events. Using @input and :value will not work correctly with this component. Update the handler signature to accept a string value directly instead of an Event object.

Suggested fix
-function handleTextInput(event: Event) {
-  const target = event.target as HTMLInputElement
-  emit('update:text', target.value)
-}
+function handleTextInput(value: string) {
+  emit('update:text', value)
+}
           <InputBase
             id="filter-search"
             type="text"
-            :value="filters.text"
+            :model-value="filters.text"
             :placeholder="searchPlaceholder"
             autocomplete="off"
             class="w-full min-w-25"
             size="medium"
             noCorrect
-            `@input`="handleTextInput"
+            `@update`:modelValue="handleTextInput"
           />
🧹 Nitpick comments (1)
app/components/Input/Base.vue (1)

2-8: Prop name shadows imported utility.

The prop noCorrect (line 8) shadows the imported noCorrect utility (line 2). While this works because you access the utility via props.noCorrect ? noCorrect : undefined, the naming could be clearer.

Consider renaming the prop to disableCorrect or similar to avoid confusion with the imported utility object.

♻️ Suggested rename
-import { noCorrect } from '~/utils/input'
+import { noCorrect as noCorrectAttrs } from '~/utils/input'

 const props = withDefaults(
   defineProps<{
     modelValue?: string
     size?: 'small' | 'medium' | 'large'
     noCorrect?: boolean
   }>(),

Then update line 41:

-    v-bind="props.noCorrect ? noCorrect : undefined"
+    v-bind="props.noCorrect ? noCorrectAttrs : undefined"

@alexdln
Copy link
Member Author

alexdln commented Feb 7, 2026

I'm afraid I need rounded-l here, not rounded-is, since that component doesn't change its direction at all. I'm looking for a way to ignore this error

@danielroe
Copy link
Member

I'm afraid I need rounded-l here, not rounded-is, since that component doesn't change its direction at all. I'm looking for a way to ignore this error

cc: @userquin

@alexdln
Copy link
Member Author

alexdln commented Feb 7, 2026

Oh, it was wrong before as well. I've restored this fragment, I hope I'll find time later to polish these pages too and improve them for rtl

@userquin
Copy link
Member

userquin commented Feb 7, 2026

I'm afraid I need rounded-l here, not rounded-is, since that component doesn't change its direction at all. I'm looking for a way to ignore this error

cc: @userquin

we can add a custom rule/shorcut for this

@alexdln
Copy link
Member Author

alexdln commented Feb 7, 2026

I think it would be useful to leave the option to skip the error for now (for example, by writing the reason and continuing to receive warnings)

Essentially, these are places where we haven't yet worked out the RTL perfectly and we have a group of elements going from left to right. We probably need to collect all these elements and understand how they should look, and then continue following this guide for these situations...

@vercel
Copy link

vercel bot commented Feb 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 8, 2026 6:34pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 8, 2026 6:34pm
npmx-lunaria Ignored Ignored Feb 8, 2026 6:34pm

Request Review

@userquin
Copy link
Member

userquin commented Feb 7, 2026

I'm afraid I need rounded-l here, not rounded-is, since that component doesn't change its direction at all. I'm looking for a way to ignore this error

Use force-rounded-l once #1179 merged

@alexdln
Copy link
Member Author

alexdln commented Feb 7, 2026

Huge thanks @userquin

@danielroe
Copy link
Member

(it's merged)

Copy link
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/Header/SearchBox.vue (1)

14-14: ⚠️ Potential issue | 🟡 Minor

Remove unused emits or wire them up.

The blur and focus emits are defined but never called—the handlers at lines 117–118 only update local state. If parent components rely on these events, add emit('focus') and emit('blur') to the handlers; otherwise, remove the unused defineEmits declaration.

Option A: Remove if unused
-const emit = defineEmits(['blur', 'focus'])
Option B: Wire up if needed
-            `@focus`="isSearchFocused = true"
-            `@blur`="isSearchFocused = false"
+            `@focus`="isSearchFocused = true; emit('focus', $event)"
+            `@blur`="isSearchFocused = false; emit('blur', $event)"
🧹 Nitpick comments (1)
app/components/Input/Base.vue (1)

38-45: Consider renaming to avoid shadowing confusion.

The prop noCorrect shadows the imported noCorrect utility, making line 42 harder to read at a glance. While props.noCorrect vs noCorrect is technically unambiguous, this naming collision may confuse future maintainers.

Consider renaming the prop (e.g., disableAutoCorrect) or aliasing the import (e.g., import { noCorrect as noCorrectAttrs }).

@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 78.26087% with 5 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/pages/index.vue 0.00% 1 Missing and 2 partials ⚠️
app/components/Header/SearchBox.vue 0.00% 0 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

)

const emit = defineEmits<{
'update:modelValue': [value: string]
Copy link
Member

Choose a reason for hiding this comment

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

let' use defineModel for every prop/emit pair...

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, looks much better now (I don’t remember why I made it so complicated)

defineExpose({
focus: () => el.value?.focus(),
blur: () => el.value?.blur(),
getBoundingClientRect: () => el.value?.getBoundingClientRect(),
Copy link
Member

Choose a reason for hiding this comment

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

do we need this one anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, and it doesn't seem to be useful, I'll remove it, thanks

:placeholder="$t('org.members.username_placeholder')"
v-bind="noCorrect"
class="w-full px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70"
noCorrect
Copy link
Member

Choose a reason for hiding this comment

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

normally we'd do kebab-cased no-correct in a template.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, I forget every time, even if there is nothing more logical than kebab in the markup...

Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

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

great work! just added a couple of small comments from a vue pov

Copy link
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

Merged via the queue into npmx-dev:main with commit de2f5e3 Feb 8, 2026
17 checks passed
@alexdln alexdln deleted the feat/add-input-component branch February 8, 2026 18:41
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.

feat(ui): Add input component

4 participants