Skip to content

Commit fe64935

Browse files
feat(form): radio input (#1217)
* feat: add radioInput component * feat: add radioInput component * feat: update form in demo app * feat: change name value * feat: change options * refactor: remove unused pages * style: fix the position of style for radio input in css file * fix: update the styles * fix: update the styles * refactor: iterate through option in ui rather than in form component
1 parent 995ae9f commit fe64935

12 files changed

Lines changed: 140 additions & 5 deletions

File tree

apps/demo/src/Views/Form/components/FormInput/FormInput.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export const FormInputDemo = () => {
4242
.nonempty({ message: t("formInput.message.required") }),
4343
typeahead: zod.string().min(1, t("formInput.message.required")),
4444
date: zod.string().date(),
45+
radioInput: zod.string(),
4546
});
4647

4748
const handleSubmit = (_formData: any) => {

apps/demo/src/Views/Form/components/FormInput/FormInputFields.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
FormActions,
44
TextInput,
55
Password,
6+
RadioInput,
67
Input,
78
useFormContext,
89
NumberInput,
@@ -154,6 +155,15 @@ export const FormInputFields = ({ checkFilledState }: Properties) => {
154155
showValidState={valid}
155156
showInvalidState={invalid}
156157
/>
158+
<RadioInput
159+
label={t("formInput.label.radioInput")}
160+
name="radioInput"
161+
options={[
162+
{ label: "One", value: "value 1" },
163+
{ label: "Two", value: "value 2" },
164+
{ label: "Three", value: "value 3" },
165+
]}
166+
/>
157167
<FormActions
158168
actions={[
159169
{

apps/demo/src/Views/Ui/components/GridContainerDemo.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { useTranslation } from "@dzangolab/react-i18n";
22
import { Page, GridContainer } from "@dzangolab/react-ui";
3-
import React from "react";
43

54
import { Package } from "../../Home/components/Package";
65

7-
const GridContainerDemo: React.FC = () => {
6+
export const GridContainerDemo = () => {
87
const { t } = useTranslation("ui");
98

109
const packages = [
@@ -48,5 +47,3 @@ const GridContainerDemo: React.FC = () => {
4847
</Page>
4948
);
5049
};
51-
52-
export default GridContainerDemo;

apps/demo/src/Views/Ui/pages.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
TextareaDemo,
2121
TypeaheadDemo,
2222
} from "./components/FormWidgets";
23+
import { GridContainerDemo } from "./components/GridContainerDemo";
2324
import { LoadingDemo } from "./components/Loading";
2425
import { MessageDemo } from "./components/Message";
2526
import { ModalDemo } from "./components/ModalDemo";
@@ -34,7 +35,6 @@ import { TagDemo } from "./components/Tag/Tag";
3435
import { TooltipDemo } from "./components/Tooltip";
3536
import { YoutubeFacadeDemo } from "./components/YoutubeFacade";
3637
import { Demo } from "../../components/Demo";
37-
import GridContainerDemo from "./components/GridContainerDemo";
3838

3939
export const UI_ROUTES = {
4040
BUTTON: "/ui/button",

apps/demo/src/locales/en/form.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"invalid": "Show invalid state",
4747
"number": "Number",
4848
"password": "Password",
49+
"radioInput": "Radio input",
4950
"readOnly": "ReadOnly input",
5051
"select": "Select",
5152
"text": "Text input",

apps/demo/src/locales/fr/form.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"invalid": "Show invalid state (fr)",
4747
"number": "Number (fr)",
4848
"password": "Password (fr)",
49+
"radioInput": "Radio input (fr)",
4950
"readOnly": "ReadOnly input (fr)",
5051
"select": "Select (fr)",
5152
"text": "Text input (fr)",
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {
2+
RadioInput as BasicRadioInput,
3+
IRadioInputProperties,
4+
} from "@dzangolab/react-ui";
5+
import React from "react";
6+
import { Controller, useFormContext } from "react-hook-form";
7+
8+
interface IRadioInput extends IRadioInputProperties {
9+
disabled?: boolean;
10+
name: string;
11+
showInvalidState?: boolean;
12+
showValidState?: boolean;
13+
submitCount?: number;
14+
}
15+
16+
export const RadioInput: React.FC<IRadioInput> = ({
17+
className,
18+
disabled,
19+
label,
20+
name,
21+
options,
22+
showInvalidState = true,
23+
showValidState = true,
24+
submitCount = 0,
25+
...others
26+
}) => {
27+
const { control, getFieldState } = useFormContext();
28+
29+
const { error, invalid } = getFieldState(name);
30+
31+
const checkInvalidState = () => {
32+
if (showInvalidState && invalid) return true;
33+
if (showValidState && !invalid) return false;
34+
};
35+
36+
return (
37+
<Controller
38+
name={name}
39+
control={control}
40+
render={({ field }) => (
41+
<BasicRadioInput
42+
name={field.name}
43+
label={label}
44+
value={field.value}
45+
disabled={disabled}
46+
errorMessage={error?.message}
47+
onChange={field.onChange}
48+
options={options}
49+
hasError={submitCount > 0 ? checkInvalidState() : undefined}
50+
{...others}
51+
/>
52+
)}
53+
/>
54+
);
55+
};

packages/form/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from "./FormProvider";
1010
export * from "./Input";
1111
export * from "./NumberInput";
1212
export * from "./Password";
13+
export * from "./RadioInput";
1314
export * from "./Select";
1415
export * from "./Textarea";
1516
export * from "./TextInput";
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { InputHTMLAttributes } from "react";
2+
3+
interface IOption {
4+
label: string;
5+
value: string;
6+
}
7+
export interface IRadioInputProperties
8+
extends InputHTMLAttributes<HTMLInputElement> {
9+
disabled?: boolean;
10+
errorMessage?: string;
11+
hasError?: boolean;
12+
helperText?: string;
13+
label?: string | React.ReactNode;
14+
name?: string;
15+
options: IOption[];
16+
}
17+
18+
export const RadioInput: React.FC<IRadioInputProperties> = ({
19+
className = "",
20+
disabled,
21+
errorMessage,
22+
hasError,
23+
helperText,
24+
label = "",
25+
name,
26+
onChange,
27+
options,
28+
value,
29+
...others
30+
}) => {
31+
return (
32+
<div className={`field ${className}`.trim()}>
33+
{label}
34+
{options?.map(({ label: optionLabel, value: optionValue }) => (
35+
<div className="radio-button-wrapper" key={optionValue}>
36+
<input
37+
aria-invalid={hasError}
38+
checked={optionValue === value}
39+
disabled={disabled}
40+
id={optionValue}
41+
name={name}
42+
onChange={onChange}
43+
type="radio"
44+
value={optionValue}
45+
{...others}
46+
></input>
47+
{optionLabel && <label htmlFor={optionValue}>{optionLabel}</label>}
48+
</div>
49+
))}
50+
{helperText && <span className="helper-text">{helperText}</span>}
51+
{errorMessage && <span className="error-message">{errorMessage}</span>}
52+
</div>
53+
);
54+
};

packages/ui/src/FormWidgets/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./Checkbox";
22
export * from "./DebouncedInput";
33
export * from "./Input";
4+
export * from "./RadioInput";
45
export * from "./Select";
56
export * from "./SwitchInput";
67
export * from "./TextArea";

0 commit comments

Comments
 (0)