Skip to content

Commit

Permalink
feat: Form widget (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
totraev committed Dec 12, 2024
1 parent a8049c4 commit 723e140
Show file tree
Hide file tree
Showing 39 changed files with 870 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"@babylonlabs-io/bbn-core-ui": minor
---

add form control component
add Form widget
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
storybook-static

# Editor directories and files
.vscode/*
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @babylonlabs-io/bbn-core-ui

## 0.5.0

### Minor Changes

- a8049c4: add form control component

## 0.4.1

### Patch Changes
Expand Down
63 changes: 59 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@babylonlabs-io/bbn-core-ui",
"version": "0.4.1",
"version": "0.5.0",
"type": "module",
"types": "dist/index.d.ts",
"publishConfig": {
Expand Down Expand Up @@ -37,7 +37,8 @@
"peerDependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tailwind-merge": "^2.5.4"
"tailwind-merge": "^2.5.4",
"yup": "^1.5.0"
},
"devDependencies": {
"@changesets/cli": "^2.27.9",
Expand Down Expand Up @@ -87,7 +88,9 @@
]
},
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@popperjs/core": "^2.11.8",
"react-hook-form": "^7.54.0",
"react-popper": "^2.3.0"
}
}
23 changes: 23 additions & 0 deletions src/components/Form/FormControl.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.bbn-form-control {
@apply flex flex-col;

&-title {
@apply mb-2 flex items-center text-sm text-primary-light;
}

&-hint {
@apply mt-1 text-sm;

&.bbn-form-control-hint-error {
@apply text-error-main;
}

&.bbn-form-control-hint-warning {
@apply text-warning-main;
}

&.bbn-form-control-hint-success {
@apply text-success-main;
}
}
}
38 changes: 38 additions & 0 deletions src/components/Form/FormControl.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Meta, StoryObj } from "@storybook/react";

import { FormControl } from "./FormControl";
import { Input } from "./Input";

const meta: Meta<typeof FormControl> = {
component: FormControl,
tags: ["autodocs"],
};

export default meta;

type Story = StoryObj<typeof FormControl>;

export const Default: Story = {
args: {
label: "Label",
children: <Input defaultValue="Hello" />,
hint: "Some random hint",
},
};

export const WithoutLabel: Story = {
args: {
children: <Input defaultValue="Hello Error" state="error" />,
hint: "Some random error",
state: "error",
},
};

export const WithError: Story = {
args: {
label: "Label",
children: <Input defaultValue="Hello Error" state="error" />,
hint: "Some random error",
state: "error",
},
};
27 changes: 27 additions & 0 deletions src/components/Form/FormControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type PropsWithChildren } from "react";
import { twJoin } from "tailwind-merge";
import "./FormControl.css";

export interface FormControlProps extends PropsWithChildren {
label?: string | JSX.Element;
hint?: string | JSX.Element;
state?: "default" | "error" | "warning" | "success";
className?: string;
}

export function FormControl({ children, label, hint, state = "default", className }: FormControlProps) {
return (
<div className={twJoin("bbn-form-control", className)}>
{label ? (
<label className="bbn-form-control-label">
<div className="bbn-form-control-title">{label}</div>
{children}
</label>
) : (
children
)}

{hint && <div className={twJoin("bbn-form-control-hint", `bbn-form-control-hint-${state}`)}>{hint}</div>}
</div>
);
}
36 changes: 16 additions & 20 deletions src/components/Form/Input.css
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
.bbn-input {
@apply relative flex flex-col;
@apply flex items-center rounded border border-primary-light/20 bg-secondary-contrast px-4 py-2 text-primary-light transition-colors;

&-wrapper {
@apply flex items-center rounded border border-primary-light/20 bg-secondary-contrast px-4 py-2 text-primary-light transition-colors;

&:focus-within {
@apply border-primary-light;
}
&:focus-within {
@apply border-primary-light;
}

&.bbn-input-error {
@apply border-error-main;
}
&.bbn-input-error {
@apply border-error-main;
}

&.bbn-input-warning {
@apply border-warning-main;
}
&.bbn-input-warning {
@apply border-warning-main;
}

&.bbn-input-success {
@apply border-success-main;
}
&.bbn-input-success {
@apply border-success-main;
}

&.bbn-input-disabled {
@apply opacity-50 pointer-events-none;
}
&.bbn-input-disabled {
@apply pointer-events-none opacity-50;
}

&-field {
Expand All @@ -36,4 +32,4 @@
&-prefix {
@apply mr-2 flex items-center text-primary-light/50;
}
}
}
10 changes: 1 addition & 9 deletions src/components/Form/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ export const Disabled: Story = {
},
};

export const WithError: Story = {
args: {
placeholder: "Input with error",
state: "error",
hint: "This field is required",
},
};

export const WithSuffix: Story = {
args: {
placeholder: "Search...",
Expand Down Expand Up @@ -63,7 +55,7 @@ export const LoadingWithInteraction: Story = {
<Input
placeholder="Click search to see loading"
suffix={
<button onClick={handleSearch} disabled={isLoading} className="h-5 w-5">
<button onClick={handleSearch} disabled={isLoading} className="size-5">
{isLoading ? <Loader size={20} /> : <RiSearchLine size={20} />}
</button>
}
Expand Down
21 changes: 6 additions & 15 deletions src/components/Form/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
import { forwardRef, type DetailedHTMLProps, type InputHTMLAttributes, type ReactNode } from "react";
import { twJoin } from "tailwind-merge";
import "./Input.css";
import { FormControl } from "./components/FormControl";

export interface InputProps
extends Omit<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "prefix" | "suffix"> {
className?: string;
wrapperClassName?: string;
prefix?: ReactNode;
suffix?: ReactNode;
disabled?: boolean;
state?: "default" | "error" | "warning";
hint?: string;
label?: string;
}

export const Input = forwardRef<HTMLInputElement, InputProps>(
(
{ className, wrapperClassName, prefix, suffix, disabled = false, state = "default", hint, label, ...props },
ref,
) => {
({ className, prefix, suffix, disabled = false, state = "default", ...props }, ref) => {
return (
<FormControl label={label} hint={hint} state={state} wrapperClassName={wrapperClassName}>
<div className={twJoin("bbn-input-wrapper", disabled && "bbn-input-disabled", `bbn-input-${state}`)}>
{prefix && <div className="bbn-input-prefix">{prefix}</div>}
<input ref={ref} className={twJoin("bbn-input-field", className)} disabled={disabled} {...props} />
{suffix && <div className="bbn-input-suffix">{suffix}</div>}
</div>
</FormControl>
<div className={twJoin("bbn-input", disabled && "bbn-input-disabled", `bbn-input-${state}`)}>
{prefix && <div className="bbn-input-prefix">{prefix}</div>}
<input ref={ref} className={twJoin("bbn-input-field", className)} disabled={disabled} {...props} />
{suffix && <div className="bbn-input-suffix">{suffix}</div>}
</div>
);
},
);
Expand Down
1 change: 0 additions & 1 deletion src/components/Form/Select.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.bbn-select {
@apply relative flex w-full cursor-pointer items-center justify-between rounded border border-primary-light bg-secondary-contrast px-4 py-2 text-sm text-primary-light outline-none transition-all;
width: var(--select-width, auto);

&:focus-visible {
@apply border-primary-light ring-1 ring-primary-light;
Expand Down
Loading

0 comments on commit 723e140

Please sign in to comment.