-
Notifications
You must be signed in to change notification settings - Fork 8
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
New input component #1577
Conversation
✅ Deploy Preview for harness-design ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for harness-xd-review ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
988b7f7
to
9a8f9d4
Compare
let inputValue = e.target.value | ||
|
||
// When type="number", we need to check if decimals are allowed | ||
if (!allowDecimal && inputValue.includes('.')) { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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?
packages/ui/src/components/form-input/components/text-input.tsx
Outdated
Show resolved
Hide resolved
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'> { |
There was a problem hiding this comment.
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
interface SearchInputProps extends Omit<InputProps, 'type' | 'onChange' | 'label'> { | |
interface SearchInputProps extends Omit<InputProps, 'type' | 'label'> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/ui/src/components/form-input/components/number-input.tsx
Outdated
Show resolved
Hide resolved
7886ba5
to
7f155ac
Compare
} | ||
|
||
if (!formContext) { | ||
throw new Error( |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
.
c14f356
to
e27c2cc
Compare
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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.
packages/ui/src/views/repo/webhooks/webhook-create/repo-webhook-create-page.tsx
Outdated
Show resolved
Hide resolved
toRepository={(repo: RepositoryType) => routes.toRepoSummary({ spaceId, repoId: repo.name })} | ||
toCreateRepo={() => routes.toCreateRepo({ spaceId })} | ||
toImportRepo={() => routes.toImportRepo({ spaceId })} | ||
toImportMultipleRepos={() => routes.toImportMultipleRepos({ spaceId })} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to that
packages/ui/src/components/form-input/components/form-text-input.tsx
Outdated
Show resolved
Hide resolved
packages/ui/src/components/git-commit-dialog/git-commit-dialog.tsx
Outdated
Show resolved
Hide resolved
Regarding #1577 (comment)
|
e767ba7
to
2180d14
Compare
bf9ce7a
to
9b22178
Compare
There was a problem hiding this 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
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value: "default | success | danger | warning", | |
value: "'default' | 'success' | 'danger' | 'warning'", |
description: "Size of the input field", | ||
required: false, | ||
defaultValue: "default", | ||
value: "default | sm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: |
There was a problem hiding this comment.
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?
<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> | ||
) }`} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return ( | ||
<SearchInput | ||
placeholder="Type to search..." | ||
onChange={(value) => setSearchValue(value)} | ||
/> | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
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)}> |
There was a problem hiding this comment.
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'>, |
There was a problem hiding this comment.
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!
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 |
There was a problem hiding this comment.
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?
This PR contains changes for
All these components are updated in the docs. Please check.
TextInput
SearchInput
NumberInput
Form usage
Features
error
ortheme
prop explicitly. Based on the presence of validation error for the given field,FormInput.Text
can switch between themes.TextInput
component has a built in logic to generate random ID to supporthtmlFor
prop ofLabel
.Screen.Recording.2025-05-11.at.12.29.11.AM.mov