refactor radio buttons, add checkbox input type to react lib

This commit is contained in:
Matthias Nannt
2022-11-23 10:10:52 +01:00
parent 0982506d1c
commit 2a23326dad
10 changed files with 159 additions and 19 deletions

View File

@@ -1,4 +1,5 @@
export * from "./inputs/Button";
export * from "./inputs/Checkbox";
export * from "./inputs/Radio";
export * from "./inputs/Submit";
export * from "./inputs/Text";

View File

@@ -1,4 +1,3 @@
import clsx from "clsx";
import React, { useMemo } from "react";
import { getElementId } from "../../lib/element";
import { useEffectUpdateSchema } from "../../lib/schema";

View File

@@ -0,0 +1,90 @@
import clsx from "clsx";
import React, { useMemo } from "react";
import { useFormContext } from "react-hook-form";
import { getElementId } from "../../lib/element";
import { normalizeOptions } from "../../lib/options";
import { useEffectUpdateSchema } from "../../lib/schema";
import { getValidationRules } from "../../lib/validation";
import { NameRequired, OptionsArray, OptionsObjectArray, UniversalInputProps } from "../../types";
import { Fieldset } from "../shared/Fieldset";
import { Help } from "../shared/Help";
import { Inner } from "../shared/Inner";
import { Label } from "../shared/Label";
import { Legend } from "../shared/Legend";
import { Messages } from "../shared/Messages";
import { Option } from "../shared/Option";
import { Options } from "../shared/Options";
import { Outer } from "../shared/Outer";
import { Wrapper } from "../shared/Wrapper";
interface CheckboxInputUniqueProps {
options?: OptionsArray | OptionsObjectArray;
fieldsetClassName?: string;
legendClassName?: string;
optionsClassName?: string;
optionClassName?: string;
}
type FormbricksProps = CheckboxInputUniqueProps & UniversalInputProps & NameRequired;
const inputType = "checkbox";
export function Checkbox(props: FormbricksProps) {
const elemId = useMemo(() => getElementId(props.id, props.name), [props.id, props.name]);
const options = useMemo(() => normalizeOptions(props.options), [props.options]);
useEffectUpdateSchema(props, inputType);
const { register } = useFormContext();
const validationRules = getValidationRules(props.validation);
if (!options || options.length === 0) {
return (
<Outer inputType={inputType} outerClassName={props.outerClassName}>
<Wrapper wrapperClassName={props.wrapperClassName}>
<Inner innerClassName={props.innerClassName}>
<input
className={clsx("formbricks-input", props.inputClassName)}
type="checkbox"
id={elemId}
{...register(props.name, {
required: { value: "required" in validationRules, message: "This field is required" },
})}
/>
<Label label={props.label} elemId={elemId} />
</Inner>
</Wrapper>
<Help help={props.help} elemId={elemId} />
<Messages {...props} />
</Outer>
);
}
return (
<Outer inputType={inputType} outerClassName={props.outerClassName}>
<Fieldset fieldsetClassName={props.fieldsetClassName} name={props.name}>
<Legend legendClassName={props.legendClassName}>{props.label}</Legend>
<Help help={props.help} elemId={elemId} />
<Options optionsClassName={props.optionsClassName}>
{options.map((option) => (
<Option optionClassName={props.optionClassName}>
<Wrapper wrapperClassName={props.wrapperClassName}>
<Inner innerClassName={props.innerClassName}>
<input
className={clsx("formbricks-input", props.inputClassName)}
type="checkbox"
id={`${props.name}-${option.value}`}
value={option.value}
disabled={option?.config?.disabled}
{...register(props.name)}
/>
<Label label={option.label} elemId={`${props.name}-${option.value}`} />
</Inner>
</Wrapper>
</Option>
))}
</Options>
</Fieldset>
<Messages {...props} />
</Outer>
);
}

View File

@@ -6,15 +6,23 @@ import { normalizeOptions } from "../../lib/options";
import { useEffectUpdateSchema } from "../../lib/schema";
import { getValidationRules } from "../../lib/validation";
import { NameRequired, OptionsArray, OptionsObjectArray, UniversalInputProps } from "../../types";
import { Fieldset } from "../shared/Fieldset";
import { Help } from "../shared/Help";
import { Inner } from "../shared/Inner";
import { Label } from "../shared/Label";
import { Legend } from "../shared/Legend";
import { Messages } from "../shared/Messages";
import { Option } from "../shared/Option";
import { Options } from "../shared/Options";
import { Outer } from "../shared/Outer";
import { Wrapper } from "../shared/Wrapper";
interface RadioInputUniqueProps {
options?: OptionsArray | OptionsObjectArray;
fieldsetClassName?: string;
legendClassName?: string;
optionsClassName?: string;
optionClassName?: string;
}
type FormbricksProps = RadioInputUniqueProps & UniversalInputProps & NameRequired;
@@ -26,10 +34,7 @@ export function Radio(props: FormbricksProps) {
const options = useMemo(() => normalizeOptions(props.options), [props.options]);
useEffectUpdateSchema(props, inputType);
const {
register,
formState: { errors },
} = useFormContext();
const { register } = useFormContext();
const validationRules = getValidationRules(props.validation);
if (!options || options.length === 0) {
@@ -56,12 +61,12 @@ export function Radio(props: FormbricksProps) {
return (
<Outer inputType={inputType} outerClassName={props.outerClassName}>
<fieldset className="formbricks-fieldset" name={props.name}>
<legend className="formbricks-legend">{props.label}</legend>
<Fieldset fieldsetClassName={props.fieldsetClassName} name={props.name}>
<Legend legendClassName={props.legendClassName}>{props.label}</Legend>
<Help help={props.help} elemId={elemId} />
<div className="formbricks-options">
<Options optionsClassName={props.optionsClassName}>
{options.map((option) => (
<div className="formbricks-option">
<Option optionClassName={props.optionClassName}>
<Wrapper wrapperClassName={props.wrapperClassName}>
<Inner innerClassName={props.innerClassName}>
<input
@@ -75,10 +80,10 @@ export function Radio(props: FormbricksProps) {
<Label label={option.label} elemId={`${props.name}-${option.value}`} />
</Inner>
</Wrapper>
</div>
</Option>
))}
</div>
</fieldset>
</Options>
</Fieldset>
<Messages {...props} />
</Outer>
);

View File

@@ -0,0 +1,16 @@
import clsx from "clsx";
import React from "react";
interface FieldsetProps {
name: string;
fieldsetClassName?: string;
children: React.ReactNode;
}
export function Fieldset({ name, fieldsetClassName, children }: FieldsetProps) {
return (
<fieldset className={clsx("formbricks-fieldset", fieldsetClassName)} name={name}>
{children}
</fieldset>
);
}

View File

@@ -0,0 +1,11 @@
import clsx from "clsx";
import React from "react";
interface LegendProps {
legendClassName?: string;
children: React.ReactNode;
}
export function Legend({ legendClassName, children }: LegendProps) {
return <legend className={clsx("formbricks-legend", legendClassName)}>{children}</legend>;
}

View File

@@ -0,0 +1,11 @@
import clsx from "clsx";
import React from "react";
interface OptionProps {
optionClassName?: string;
children: React.ReactNode;
}
export function Option({ optionClassName, children }: OptionProps) {
return <div className={clsx("formbricks-option", optionClassName)}>{children}</div>;
}

View File

@@ -0,0 +1,11 @@
import clsx from "clsx";
import React from "react";
interface OptionsProps {
optionsClassName?: string;
children: React.ReactNode;
}
export function Options({ optionsClassName, children }: OptionsProps) {
return <div className={clsx("formbricks-options", optionsClassName)}>{children}</div>;
}

View File

@@ -1,8 +1,5 @@
import clsx from "clsx";
import React from "react";
import { FieldErrorsImpl, useFormContext } from "react-hook-form";
import { Help } from "./Help";
import { Messages } from "./Messages";
interface OuterProps {
inputType: string;
@@ -11,9 +8,6 @@ interface OuterProps {
}
export function Outer({ inputType, outerClassName, children }: OuterProps) {
const {
formState: { errors },
} = useFormContext();
return (
<div className={clsx("formbricks-outer", outerClassName)} data-type={inputType}>
{children}

View File

@@ -6,6 +6,8 @@
"lib": ["ES2015", "DOM"],
"module": "ESNext",
"target": "ES6",
"jsx": "react"
"jsx": "react",
"noUnusedLocals": true,
"noUnusedParameters": true
}
}