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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/gitness/src/pages-v2/repo/repo-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export default function ReposListPage() {
toRepository={(repo: RepositoryType) => routes.toRepoSummary({ spaceId, repoId: repo.name })}
toCreateRepo={() => routes.toCreateRepo({ spaceId })}
toImportRepo={() => routes.toImportRepo({ spaceId })}
toImportMultipleRepos={() => routes.toImportMultipleRepos({ spaceId })}
/>
)
}

ReposListPage.displayName = 'ReposListPage'
69 changes: 69 additions & 0 deletions apps/portal/src/content/docs/components/form.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Form
description: Form component
---

The `Form` component is a container for form elements, providing a structured layout and validation capabilities.

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

```tsx
import { useForm } from "react-hook-form";

import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

//...

// Define the validation schema with zod
const formSchema = z.object({
inputField: z.string().min(3, "Input must be at least 3 characters"),
});

// Infer the type from the schema
type FormValues = z.infer<typeof formSchema>;

export const ExampleFormComponent = () => {
const [submittedValue, setSubmittedValue] = useState<string | null>(null);
const inputRef = useRef<HTMLInputElement | null>(null);

// Initialize react-hook-form with zod resolver
const formMethods = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
inputField: "some text",
},
});

const { register, handleSubmit } = formMethods;

// Handle form submission
const onSubmit = (data: FormValues) => {
setSubmittedValue(data.inputField);
};

return (
<div className="w-full max-w-md">
{/* ‼️ It is mandatory to pass all return values from useForm to FormWrapper */}
<FormWrapper {...formMethods} onSubmit={handleSubmit(onSubmit)}>
<FormInput.Text
ref={inputRef}
label="Input Field"
placeholder="Enter at least 3 characters"
{...register("inputField")}
/>

<Button type="submit" disabled={methods.formState.isSubmitting}>
{formMethods.formState.isSubmitting ? "Submitting..." : "Submit"}
</Button>

{submittedValue && (
<div className="mt-4 p-3 bg-green-50 text-green-800 rounded">
Submitted value: {submittedValue}
</div>
)}
</FormWrapper>
</div>
);
};
```
285 changes: 285 additions & 0 deletions apps/portal/src/content/docs/components/number-input.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
---
title: NumberInput
description: NumberInput component
---

The `NumberInput` component is used to handle user input, providing options for styling via themes and sizes.
The component also offers options for adding icons, captions, custom content, and error text for the field.

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

<DocsPage.ComponentExample
client:only
code={`<div className="flex flex-col gap-8 min-w-[400px]">
{/* Basic Number Input */}
<div className="font-bold w-full mb-2">Basic Number Input:</div>
<NumberInput id="basic-number" label="Basic Number Input" placeholder="Enter a number" />

{/* Number Input with Min/Max */}
<div className="font-bold w-full mb-2">Number Input with Min/Max Limits:</div>
<NumberInput
id="limited-range"
label="Limited Range (0-10)"
min={0}
max={10}
defaultValue={5}
onChange={(value) => console.log('Value changed:', value)}
/>

{/* Decimal Numbers */}
<div className="font-bold w-full mb-2">Decimal Numbers:</div>
<NumberInput
id="decimal-input"
allowDecimal
label="With Decimals"
decimalScale={2}
defaultValue={3.14}
/>
<NumberInput
id="integer-only"
label="Integer Only"
allowDecimal={false}
defaultValue={42}
/>

{/* Negative Values */}
<div className="font-bold w-full mb-2">Negative Values:</div>
<NumberInput
id="allow-negative"
label="Allow Negative"
defaultValue={-10}
/>
<NumberInput
id="positive-only"
label="Positive Only"
min={0}
defaultValue={10}
/>

{/* Custom Steppers */}
<div className="font-bold w-full mb-2">Custom Step Values:</div>
<NumberInput
id="small-increment"
label="Increment by 0.1"
step={0.1}
allowDecimal={true}
defaultValue={1.0}
/>
<NumberInput
id="large-increment"
label="Increment by 5"
step={5}
defaultValue={10}
/>

{/* Disabled & Error States */}
<div className="font-bold w-full mb-2">States and Feedback:</div>
<NumberInput
id="disabled-input"
label="Disabled Input"
disabled
defaultValue={50}
/>
<NumberInput
id="error-input"
label="With Error"
error="Please enter a valid number"
theme="danger"
/>
<NumberInput
id="warning-input"
label="With Warning"
warning="This is a high value"
theme="warning"
defaultValue={95}
/>
<NumberInput
id="caption-input"
label="With Caption"
caption="Enter your preferred quantity"
defaultValue={1}
/>

{/* Optional Label */}
<NumberInput
id="optional-input"
label="Optional Field"
optional={true}
/>

{/* Without Stepper UI */}
<div className="font-bold w-full mb-2">Without Stepper Buttons:</div>
<NumberInput
hideStepper
id="no-stepper"
label="No Stepper UI"
placeholder="Enter a number manually"
/>
</div>`}
/>

## Usage

```typescript jsx
import { NumberInput } from '@harnessio/ui/components'

// ..
return (
<NumberInput
integerOnly
label="Quantity"
placeholder="Enter a number"
min={0}
max={100}
defaultValue={1}
onChange={(e) => handleQuantityChange(e.target.value)}
/>
)
```

## API Reference

<DocsPage.PropsTable
props={[
{
name: "wrapperClassName",
description: "Additional CSS classes for the wrapper element",
required: false,
defaultValue: "",
value: "string",
},
{
name: "label",
description: "Label text for the input field",
required: false,
defaultValue: "",
value: "string",
},
{
name: "id",
description: "Unique identifier for the input element",
required: false,
defaultValue: "",
value: "string",
},
{
name: "disabled",
description: "Whether the input is disabled",
required: false,
defaultValue: "false",
value: "boolean",
},
{
name: "optional",
description: "Whether to display an 'optional' tag beside the label",
required: false,
defaultValue: "false",
value: "boolean",
},
{
name: "caption",
description: "Helper text displayed below the input",
required: false,
defaultValue: "",
value: "string",
},
{
name: "error",
description: "Error message to display (will use danger theme)",
required: false,
defaultValue: "",
value: "string",
},
{
name: "warning",
description: "Warning message to display (will use warning theme)",
required: false,
defaultValue: "",
value: "string",
},
{
name: "hideStepper",
description: "Whether to hide the increment/decrement buttons",
required: false,
defaultValue: "false",
value: "boolean",
},
{
name: "integerOnly",
description: "Whether to allow only integer values (no decimals)",
required: false,
defaultValue: "false",
value: "boolean",
},
{
name: "min",
description: "Minimum allowed value",
required: false,
defaultValue: "",
value: "number",
},
{
name: "max",
description: "Maximum allowed value",
required: false,
defaultValue: "",
value: "number",
},
{
name: "step",
description: "Amount to increment/decrement when using stepper buttons",
required: false,
defaultValue: "1",
value: "number",
},
{
name: "placeholder",
description: "Placeholder text for the input field",
required: false,
defaultValue: "",
value: "string",
},
{
name: "className",
description: "Additional CSS classes for the input element",
required: false,
defaultValue: "",
value: "string",
},
{
name: "theme",
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'",

},
{
name: "defaultValue",
description: "Default value for uncontrolled input",
required: false,
defaultValue: "",
value: "number",
},
{
name: "value",
description: "Controlled value for the input",
required: false,
defaultValue: "",
value: "number",
},
{
name: "onChange",
description: "Callback when value changes",
required: false,
defaultValue: "",
value: "React.ChangeEventHandler<HTMLInputElement>",
},
{
name: "size",
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'",

},
]}
/>
Loading