Skip to content

New input component #1577

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 15, 2025
Merged

New input component #1577

merged 18 commits into from
May 15, 2025

Conversation

praneshg239
Copy link
Contributor

@praneshg239 praneshg239 commented May 5, 2025

This PR contains changes for

  • TextInput
  • NumberInput
  • SearchInput
  • FormWrapper
  • FormInput.Text

All these components are updated in the docs. Please check.

TextInput

image image

SearchInput

image

NumberInput

image image image

Form usage

Features

  • Error handling and validation is encapsulated.
  • Need to pass error or theme prop explicitly. Based on the presence of validation error for the given field, FormInput.Text can switch between themes.
  • If ID is not passed, TextInput component has a built in logic to generate random ID to support htmlFor prop of Label.
// ...

<FormWrapper {...formMethods} onSubmit={methods.handleSubmit(onSubmit)}>
        <FormInput.Text
          ref={inputRef}
          name="username"
          label="Username"
          placeholder="Enter at least 3 characters"
        />
</FormWrapper>
Screen.Recording.2025-05-11.at.12.29.11.AM.mov

Copy link

netlify bot commented May 5, 2025

Deploy Preview for harness-design ready!

Name Link
🔨 Latest commit 9b22178
🔍 Latest deploy log https://app.netlify.com/projects/harness-design/deploys/682612b54217de0008f22e80
😎 Deploy Preview https://deploy-preview-1577--harness-design.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

netlify bot commented May 5, 2025

Deploy Preview for harness-xd-review ready!

Name Link
🔨 Latest commit 9b22178
🔍 Latest deploy log https://app.netlify.com/projects/harness-xd-review/deploys/682612b5470aac000842ca78
😎 Deploy Preview https://deploy-preview-1577--harness-xd-review.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

let inputValue = e.target.value

// When type="number", we need to check if decimals are allowed
if (!allowDecimal && inputValue.includes('.')) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This I have to check whether it can be removed by testing inputMode will handle this or not.


// Clean up debounced function on unmount
useEffect(() => {
const debouncedFn = debouncedOnChangeRef.current
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Search input will have debounce builtin.

}, [])

return (
<BaseInput
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should search component needs a label?

})

// Default theme props
type CaptionProps = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we rename this to match the component name?

import { BaseInput, InputProps } from './base-input'

// Custom onChange handler for search that works with strings instead of events
interface SearchInputProps extends Omit<InputProps, 'type' | 'onChange' | 'label'> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't need to omit the onChange since you're overriding it

Suggested change
interface SearchInputProps extends Omit<InputProps, 'type' | 'onChange' | 'label'> {
interface SearchInputProps extends Omit<InputProps, 'type' | 'label'> {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did the same, but ChangeEventHandler is not compatible with string. Hence we need to omit.

image

@praneshg239 praneshg239 force-pushed the new-input-component branch from 7886ba5 to 7f155ac Compare May 10, 2025 18:43
@praneshg239 praneshg239 marked this pull request as ready for review May 10, 2025 19:15
@praneshg239 praneshg239 marked this pull request as draft May 10, 2025 19:16
}

if (!formContext) {
throw new Error(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If FormInput.Text is not using within the scope of FormProvider from react-hook-from, then it will throw an exception with proper message.

field.ref = setRefs

// Determine if there's an error from the form state
const errorMessage = fieldState.error?.message || props.error
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fieldState will take precedence over props.error.

@praneshg239 praneshg239 force-pushed the new-input-component branch from c14f356 to e27c2cc Compare May 14, 2025 07:59
@praneshg239 praneshg239 marked this pull request as ready for review May 14, 2025 08:50
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doc is quite non-standard in its layout and content

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can we update the doc as separate PR?

<svg stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 15L12 9L18 15" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<svg viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
Copy link
Collaborator

Choose a reason for hiding this comment

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

Aren't these existing icons? I'd consider leaving the icons as-is for the input PR and just reference icons by name. The icons themselves can be managed separately.

toRepository={(repo: RepositoryType) => routes.toRepoSummary({ spaceId, repoId: repo.name })}
toCreateRepo={() => routes.toCreateRepo({ spaceId })}
toImportRepo={() => routes.toImportRepo({ spaceId })}
toImportMultipleRepos={() => routes.toImportMultipleRepos({ spaceId })}
Copy link
Collaborator

Choose a reason for hiding this comment

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

should this be part of this PR? maybe it came in during a rebase?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No @abhinavrastogi-harness, it was not added before because of this, multiple import repos is not working now. It is the fix for that.

<g>
<path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" stroke-linecap="round"/>
</g>
<svg viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 to that

@praneshg239
Copy link
Contributor Author

Regarding #1577 (comment)

chevron-up icon was not correct. It was different from what we are using in figma. Hence updated right icon from figma to match the mock. Else, number input spin will look different from what we have in figma.

@praneshg239 praneshg239 force-pushed the new-input-component branch from e767ba7 to 2180d14 Compare May 15, 2025 07:11
@praneshg239 praneshg239 force-pushed the new-input-component branch from bf9ce7a to 9b22178 Compare May 15, 2025 16:13
Copy link
Collaborator

@knagurski knagurski left a comment

Choose a reason for hiding this comment

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

No blockers. We can follow up on most of this stuff in follow up PRs. Great work

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we drop this file from the PR since it'll need rewritten

description: "Theme styling for the input and caption",
required: false,
defaultValue: "default",
value: "default | success | danger | warning",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
value: "default | success | danger | warning",
value: "'default' | 'success' | 'danger' | 'warning'",

description: "Size of the input field",
required: false,
defaultValue: "default",
value: "default | sm",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
value: "default | sm",
value: "'default' | 'sm'",


import { DocsPage } from "@/components/docs-page";

Below is an example of how to implement a search input that displays the current search value using React state. The SearchInput component includes a built-in 300ms debounce to prevent excessive callbacks when typing:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we reword this to describe the component rather than the example?

Comment on lines +10 to +29
<DocsPage.ComponentExample client:only code={`() => {
// Using useState hook to track search value
const [searchValue, setSearchValue] = React.useState("");

return (

<div className="flex flex-col gap-6 min-w-[400px]">
<div className="mb-2 w-full font-bold mt-6">Search with State:</div>
<SearchInput
placeholder="Type to search..."
onChange={(value) => setSearchValue(value)}
/>
<div className="rounded-md border p-3">
<div className="text-sm font-medium underline underline-offset-2">
Current Search Value:
</div>
<p className="mt-1 font-mono text-sm">{searchValue || "(empty)"}</p>
</div>
</div>
) }`} />
Copy link
Collaborator

Choose a reason for hiding this comment

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

The indentation looks off in this example. Since it's seen by prettier as a string, we need to manually indent examples.
Screenshot 2025-05-15 at 14 38 12

Comment on lines +38 to +43
return (
<SearchInput
placeholder="Type to search..."
onChange={(value) => setSearchValue(value)}
/>
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return (
<SearchInput
placeholder="Type to search..."
onChange={(value) => setSearchValue(value)}
/>
)
return (
<SearchInput
placeholder="Type to search..."
onChange={(value) => setSearchValue(value)}
/>
)

import { FormTextInput } from './components/form-text-input'

const FormInput = {
Text: FormTextInput
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can follow up, but if we have a use-case of a numeric input at all, we have a use-case of using it within a form without needing to wire it up manually.

const effectiveIconName = theme === 'danger' ? 'cross-circle' : 'warning-triangle-outline'

return (
<p className={cn(formCaptionVariants({ theme }), className)}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Must see if there's an appropriate role to use and how we can link it a form element. As-is screen readers will not associate anything in this with the form element. We can follow up in a future PR.

}

export interface BaseInputProps
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix' | 'suffix'>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

HTML elements do not have the concept of suffix. prefix is back from the DHTML days when HTML was trying to be XML!

Suggested change
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix' | 'suffix'>,
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'>,

return <span className={cn('cn-input-affix', isPrefix ? 'cn-input-prefix' : 'cn-input-suffix')}>{children}</span>
}

export interface BaseInputProps
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to export this? It's called BaseInputProps, but it's not the props to the BaseInput component (InputProps has that privilege). Can we just make this part of line 42?

@praneshg239 praneshg239 merged commit 06aa8ab into main May 15, 2025
20 checks passed
@praneshg239 praneshg239 deleted the new-input-component branch May 15, 2025 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants