mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-30 02:29:45 -05:00
Add Input Types: Checkbox, Email, Number, Password, Phone, Radio, Search, Url | Add validations: accepted, email, url
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@formbricks/react": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add Input Types: Checkbox, Email, Number, Password, Phone, Radio, Search, Url | Add validations: accepted, email, url
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Text, Textarea } from "..";
|
||||||
import { Form } from "./Form";
|
import { Form } from "./Form";
|
||||||
import { Text, Textarea } from "./Inputs";
|
|
||||||
|
|
||||||
interface OnSubmitProps {
|
interface OnSubmitProps {
|
||||||
data: any;
|
data: any;
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
export * from "./inputs/Button";
|
|
||||||
export * from "./inputs/Checkbox";
|
|
||||||
export * from "./inputs/Radio";
|
|
||||||
export * from "./inputs/Submit";
|
|
||||||
export * from "./inputs/Text";
|
|
||||||
export * from "./inputs/Textarea";
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { getElementId } from "../../lib/element";
|
import { getElementId } from "../../lib/element";
|
||||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
import { SVGComponent, UniversalInputProps } from "../../types";
|
import { SVGComponent, UniversalInputProps } from "../../types";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React, { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { getElementId } from "../../lib/element";
|
import { getElementId } from "../../lib/element";
|
||||||
import { normalizeOptions } from "../../lib/options";
|
import { normalizeOptions } from "../../lib/options";
|
||||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
import { getValidationRules } from "../../lib/validation";
|
import { getValidationRules, validate } from "../../lib/validation";
|
||||||
import { NameRequired, OptionsArray, OptionsObjectArray, UniversalInputProps } from "../../types";
|
import { NameRequired, OptionsArray, OptionsObjectArray, UniversalInputProps } from "../../types";
|
||||||
import { Fieldset } from "../shared/Fieldset";
|
import { Fieldset } from "../shared/Fieldset";
|
||||||
import { Help } from "../shared/Help";
|
import { Help } from "../shared/Help";
|
||||||
@@ -48,6 +48,7 @@ export function Checkbox(props: FormbricksProps) {
|
|||||||
id={elemId}
|
id={elemId}
|
||||||
{...register(props.name, {
|
{...register(props.name, {
|
||||||
required: { value: "required" in validationRules, message: "This field is required" },
|
required: { value: "required" in validationRules, message: "This field is required" },
|
||||||
|
validate: validate(validationRules),
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Label label={props.label} elemId={elemId} />
|
<Label label={props.label} elemId={elemId} />
|
||||||
@@ -66,7 +67,7 @@ export function Checkbox(props: FormbricksProps) {
|
|||||||
<Help help={props.help} elemId={elemId} />
|
<Help help={props.help} elemId={elemId} />
|
||||||
<Options optionsClassName={props.optionsClassName}>
|
<Options optionsClassName={props.optionsClassName}>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<Option optionClassName={props.optionClassName}>
|
<Option key={`${props.name}-${option.value}`} optionClassName={props.optionClassName}>
|
||||||
<Wrapper wrapperClassName={props.wrapperClassName}>
|
<Wrapper wrapperClassName={props.wrapperClassName}>
|
||||||
<Inner innerClassName={props.innerClassName}>
|
<Inner innerClassName={props.innerClassName}>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface EmailUniqueProps {
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = EmailUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "email";
|
||||||
|
|
||||||
|
export function Email(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface InputUniqueProps {
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
step?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = InputUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "number";
|
||||||
|
|
||||||
|
export function Number(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
|
additionalValidation={{
|
||||||
|
min: {
|
||||||
|
value: props.min,
|
||||||
|
message: `The minimum number allowed is ${props.min}`,
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
value: props.max,
|
||||||
|
message: `The minimum number allowed is ${props.max}`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
additionalProps={{
|
||||||
|
step: props.step,
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface PasswordUniqueProps {
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = PasswordUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "password";
|
||||||
|
|
||||||
|
export function Password(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
|
additionalValidation={{
|
||||||
|
minLength: {
|
||||||
|
value: props.minLength || 0,
|
||||||
|
message: `Your answer must be at least ${props.minLength} characters long`,
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: props.maxLength || 524288,
|
||||||
|
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface PhoneUniqueProps {
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = PhoneUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "phone";
|
||||||
|
const htmlType = "tel";
|
||||||
|
|
||||||
|
export function Phone(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: htmlType, formbricks: inputType }}
|
||||||
|
additionalValidation={{
|
||||||
|
minLength: {
|
||||||
|
value: props.minLength || 0,
|
||||||
|
message: `Your answer must be at least ${props.minLength} characters long`,
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: props.maxLength || 524288,
|
||||||
|
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React, { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { getElementId } from "../../lib/element";
|
import { getElementId } from "../../lib/element";
|
||||||
import { normalizeOptions } from "../../lib/options";
|
import { normalizeOptions } from "../../lib/options";
|
||||||
@@ -66,7 +66,7 @@ export function Radio(props: FormbricksProps) {
|
|||||||
<Help help={props.help} elemId={elemId} />
|
<Help help={props.help} elemId={elemId} />
|
||||||
<Options optionsClassName={props.optionsClassName}>
|
<Options optionsClassName={props.optionsClassName}>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<Option optionClassName={props.optionClassName}>
|
<Option key={`${props.name}-${option.value}`} optionClassName={props.optionClassName}>
|
||||||
<Wrapper wrapperClassName={props.wrapperClassName}>
|
<Wrapper wrapperClassName={props.wrapperClassName}>
|
||||||
<Inner innerClassName={props.innerClassName}>
|
<Inner innerClassName={props.innerClassName}>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface SearchUniqueProps {
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = SearchUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "search";
|
||||||
|
|
||||||
|
export function Search(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
|
additionalValidation={{
|
||||||
|
minLength: {
|
||||||
|
value: props.minLength || 0,
|
||||||
|
message: `Your answer must be at least ${props.minLength} characters long`,
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: props.maxLength || 524288,
|
||||||
|
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { getElementId } from "../../lib/element";
|
import { getElementId } from "../../lib/element";
|
||||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
import { SVGComponent, UniversalInputProps } from "../../types";
|
import { SVGComponent, UniversalInputProps } from "../../types";
|
||||||
|
|||||||
@@ -1,65 +1,35 @@
|
|||||||
import clsx from "clsx";
|
|
||||||
import React, { useMemo } from "react";
|
|
||||||
import { useFormContext } from "react-hook-form";
|
|
||||||
import { getElementId } from "../../lib/element";
|
|
||||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
import { getValidationRules, validate } from "../../lib/validation";
|
|
||||||
import { NameRequired, UniversalInputProps } from "../../types";
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
import { Help } from "../shared/Help";
|
import { Input, InputProps } from "../shared/Input";
|
||||||
import { Inner } from "../shared/Inner";
|
|
||||||
import { Label } from "../shared/Label";
|
|
||||||
import { Messages } from "../shared/Messages";
|
|
||||||
import { Outer } from "../shared/Outer";
|
|
||||||
import { Wrapper } from "../shared/Wrapper";
|
|
||||||
|
|
||||||
interface TextInputUniqueProps {
|
interface TextUniqueProps {
|
||||||
maxLength?: number;
|
|
||||||
minLength?: number;
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormbricksProps = TextInputUniqueProps & UniversalInputProps & NameRequired;
|
type Props = TextUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
const inputType = "text";
|
const inputType = "text";
|
||||||
|
|
||||||
export function Text(props: FormbricksProps) {
|
export function Text(props: Props) {
|
||||||
const elemId = useMemo(() => getElementId(props.id, props.name), [props.id, props.name]);
|
|
||||||
useEffectUpdateSchema(props, inputType);
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
const {
|
|
||||||
register,
|
|
||||||
formState: { errors },
|
|
||||||
} = useFormContext();
|
|
||||||
const validationRules = getValidationRules(props.validation);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Outer inputType={inputType} outerClassName={props.outerClassName}>
|
<Input
|
||||||
<Wrapper wrapperClassName={props.wrapperClassName}>
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
<Label label={props.label} elemId={elemId} labelClassName={props.labelClassName} />
|
additionalValidation={{
|
||||||
<Inner innerClassName={props.innerClassName}>
|
minLength: {
|
||||||
<input
|
value: props.minLength || 0,
|
||||||
className={clsx("formbricks-input", props.inputClassName)}
|
message: `Your answer must be at least ${props.minLength} characters long`,
|
||||||
type="text"
|
},
|
||||||
id={elemId}
|
maxLength: {
|
||||||
placeholder={props.placeholder || ""}
|
value: props.maxLength || 524288,
|
||||||
aria-invalid={errors[props.name] ? "true" : "false"}
|
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
||||||
{...register(props.name, {
|
},
|
||||||
required: { value: "required" in validationRules, message: "This field is required" },
|
}}
|
||||||
minLength: {
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
value: props.minLength || 0,
|
{...props}
|
||||||
message: `Your answer must be at least ${props.minLength} characters long`,
|
/>
|
||||||
},
|
|
||||||
maxLength: {
|
|
||||||
value: props.maxLength || 524288,
|
|
||||||
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
|
||||||
},
|
|
||||||
validate: validate(validationRules),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</Inner>
|
|
||||||
</Wrapper>
|
|
||||||
<Help help={props.help} elemId={elemId} helpClassName={props.helpClassName} />
|
|
||||||
<Messages {...props} />
|
|
||||||
</Outer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
import { getElementId } from "../../lib/element";
|
import { getElementId } from "../../lib/element";
|
||||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Input, InputProps } from "../shared/Input";
|
||||||
|
|
||||||
|
interface UrlUniqueProps {
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = UrlUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
const inputType = "url";
|
||||||
|
|
||||||
|
export function Url(props: Props) {
|
||||||
|
useEffectUpdateSchema(props, inputType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type={{ html: inputType, formbricks: inputType }}
|
||||||
|
additionalValidation={{
|
||||||
|
minLength: {
|
||||||
|
value: props.minLength || 0,
|
||||||
|
message: `Your answer must be at least ${props.minLength} characters long`,
|
||||||
|
},
|
||||||
|
maxLength: {
|
||||||
|
value: props.maxLength || 524288,
|
||||||
|
message: `Your answer musn't be longer than ${props.maxLength} characters`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
additionalProps={{ placeholder: props.placeholder }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface HelpProps {
|
interface HelpProps {
|
||||||
help?: string;
|
help?: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
interface InnerProps {
|
interface InnerProps {
|
||||||
innerClassName?: string;
|
innerClassName?: string;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import { useFormContext } from "react-hook-form";
|
||||||
|
import { getElementId } from "../../lib/element";
|
||||||
|
import { getValidationRules, validate } from "../../lib/validation";
|
||||||
|
import { NameRequired, UniversalInputProps } from "../../types";
|
||||||
|
import { Help } from "./Help";
|
||||||
|
import { Inner } from "./Inner";
|
||||||
|
import { Label } from "./Label";
|
||||||
|
import { Messages } from "./Messages";
|
||||||
|
import { Outer } from "./Outer";
|
||||||
|
import { Wrapper } from "./Wrapper";
|
||||||
|
|
||||||
|
export interface InputProps {
|
||||||
|
additionalValidation?: any;
|
||||||
|
additionalProps?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UniqueProps {
|
||||||
|
type: {
|
||||||
|
formbricks: string;
|
||||||
|
html: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormbricksProps = UniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||||
|
|
||||||
|
export function Input(props: FormbricksProps) {
|
||||||
|
const elemId = useMemo(() => getElementId(props.id, props.name), [props.id, props.name]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
formState: { errors },
|
||||||
|
} = useFormContext();
|
||||||
|
const validationRules = getValidationRules(props.validation);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Outer inputType={props.type.formbricks} outerClassName={props.outerClassName}>
|
||||||
|
<Wrapper wrapperClassName={props.wrapperClassName}>
|
||||||
|
<Label label={props.label} elemId={elemId} labelClassName={props.labelClassName} />
|
||||||
|
<Inner innerClassName={props.innerClassName}>
|
||||||
|
<input
|
||||||
|
className={clsx("formbricks-input", props.inputClassName)}
|
||||||
|
type={props.type.html}
|
||||||
|
id={elemId}
|
||||||
|
aria-invalid={errors[props.name] ? "true" : "false"}
|
||||||
|
{...props.additionalProps}
|
||||||
|
{...register(props.name, {
|
||||||
|
required: { value: "required" in validationRules, message: "This field is required" },
|
||||||
|
validate: validate(validationRules),
|
||||||
|
...props.additionalValidation,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Inner>
|
||||||
|
</Wrapper>
|
||||||
|
<Help help={props.help} elemId={elemId} helpClassName={props.helpClassName} />
|
||||||
|
<Messages {...props} />
|
||||||
|
</Outer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface LabelProps {
|
interface LabelProps {
|
||||||
label?: string;
|
label?: string;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface LegendProps {
|
interface LegendProps {
|
||||||
legendClassName?: string;
|
legendClassName?: string;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ErrorMessage } from "@hookform/error-message";
|
import { ErrorMessage } from "@hookform/error-message";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
import { useFormContext } from "react-hook-form";
|
import { useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
interface HelpProps {
|
interface HelpProps {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface OptionProps {
|
interface OptionProps {
|
||||||
optionClassName?: string;
|
optionClassName?: string;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface OptionsProps {
|
interface OptionsProps {
|
||||||
optionsClassName?: string;
|
optionsClassName?: string;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface OuterProps {
|
interface OuterProps {
|
||||||
inputType: string;
|
inputType: string;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from "react";
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
interface WrapperProps {
|
interface WrapperProps {
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
export * from "./components/Form";
|
export * from "./components/Form";
|
||||||
export * from "./components/FormbricksSchema";
|
export * from "./components/FormbricksSchema";
|
||||||
export * from "./components/Inputs";
|
// Inputs
|
||||||
|
export * from "./components/inputs/Button";
|
||||||
|
export * from "./components/inputs/Checkbox";
|
||||||
|
export * from "./components/inputs/Email";
|
||||||
|
export * from "./components/inputs/Number";
|
||||||
|
export * from "./components/inputs/Password";
|
||||||
|
export * from "./components/inputs/Phone";
|
||||||
|
export * from "./components/inputs/Radio";
|
||||||
|
export * from "./components/inputs/Search";
|
||||||
|
export * from "./components/inputs/Submit";
|
||||||
|
export * from "./components/inputs/Text";
|
||||||
|
export * from "./components/inputs/Textarea";
|
||||||
|
export * from "./components/inputs/Url";
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ export const getValidationRules = (validation: string | undefined) => {
|
|||||||
return validationRules;
|
return validationRules;
|
||||||
}
|
}
|
||||||
for (const validationRule of validation.split("|")) {
|
for (const validationRule of validation.split("|")) {
|
||||||
|
if (validationRule === "accepted" && !("accepted" in validationRules)) {
|
||||||
|
validationRules.accepted = {};
|
||||||
|
}
|
||||||
|
if (validationRule === "email" && !("email" in validationRules)) {
|
||||||
|
validationRules.email = {};
|
||||||
|
}
|
||||||
if (validationRule === "required" && !("required" in validationRules)) {
|
if (validationRule === "required" && !("required" in validationRules)) {
|
||||||
validationRules.required = {};
|
validationRules.required = {};
|
||||||
}
|
}
|
||||||
@@ -16,12 +22,27 @@ export const getValidationRules = (validation: string | undefined) => {
|
|||||||
if (validationRule.startsWith("min:") && !("min" in validationRules)) {
|
if (validationRule.startsWith("min:") && !("min" in validationRules)) {
|
||||||
validationRules.min = { value: validationRule.split(":")[1] };
|
validationRules.min = { value: validationRule.split(":")[1] };
|
||||||
}
|
}
|
||||||
|
if (validationRule === "url" && !("url" in validationRules)) {
|
||||||
|
validationRules.url = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return validationRules;
|
return validationRules;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validate = (validationRules: any) => {
|
export const validate = (validationRules: any) => {
|
||||||
const validation: any = {};
|
const validation: any = {};
|
||||||
|
if ("accepted" in validationRules) {
|
||||||
|
validation.accepted = (v: string | boolean | number) =>
|
||||||
|
v === true || v === 1 || v === "on" || v === "yes" || `This field must be accepted`;
|
||||||
|
}
|
||||||
|
if ("email" in validationRules) {
|
||||||
|
validation.email = (v: string) =>
|
||||||
|
("email" in validationRules &&
|
||||||
|
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||||
|
v
|
||||||
|
)) ||
|
||||||
|
"Please provide a valid email address";
|
||||||
|
}
|
||||||
if ("max" in validationRules) {
|
if ("max" in validationRules) {
|
||||||
validation.max = (v: string) =>
|
validation.max = (v: string) =>
|
||||||
parseInt(v) <= validationRules.max.value ||
|
parseInt(v) <= validationRules.max.value ||
|
||||||
@@ -36,5 +57,13 @@ export const validate = (validationRules: any) => {
|
|||||||
validation.number = (v: string) =>
|
validation.number = (v: string) =>
|
||||||
("number" in validationRules && /^[+-]?([0-9]*[.])?[0-9]+$/.test(v)) || "Input must be a number";
|
("number" in validationRules && /^[+-]?([0-9]*[.])?[0-9]+$/.test(v)) || "Input must be a number";
|
||||||
}
|
}
|
||||||
|
if ("url" in validationRules) {
|
||||||
|
validation.url = (v: string) =>
|
||||||
|
("url" in validationRules &&
|
||||||
|
/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/.test(
|
||||||
|
v
|
||||||
|
)) ||
|
||||||
|
"Please provide a valid url (including http:// or https://)";
|
||||||
|
}
|
||||||
return validation;
|
return validation;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ button.formbricks-input {
|
|||||||
@apply my-2 inline-flex items-center rounded-md border border-transparent bg-slate-600 px-3 py-2 text-base font-medium leading-4 text-white shadow-sm hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2 sm:text-sm;
|
@apply my-2 inline-flex items-center rounded-md border border-transparent bg-slate-600 px-3 py-2 text-base font-medium leading-4 text-white shadow-sm hover:bg-slate-700 focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2 sm:text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].formbricks-input {
|
input[type="text"].formbricks-input,
|
||||||
|
input[type="number"].formbricks-input,
|
||||||
|
input[type="email"].formbricks-input,
|
||||||
|
input[type="password"].formbricks-input,
|
||||||
|
input[type="search"].formbricks-input,
|
||||||
|
input[type="tel"].formbricks-input,
|
||||||
|
input[type="url"].formbricks-input {
|
||||||
@apply form-input text-base block rounded-md border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm;
|
@apply form-input text-base block rounded-md border-gray-300 shadow-sm focus:border-slate-500 focus:ring-slate-500 sm:text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"lib": ["ES2015", "DOM"],
|
"lib": ["ES2015", "DOM"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"jsx": "react",
|
"jsx": "react-jsx",
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true
|
"noUnusedParameters": true
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+9
-3
@@ -10,7 +10,7 @@ importers:
|
|||||||
turbo: latest
|
turbo: latest
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@changesets/cli': 2.25.0
|
'@changesets/cli': 2.25.0
|
||||||
prettier: 2.7.1
|
prettier: 2.8.0
|
||||||
tsx: 3.9.0
|
tsx: 3.9.0
|
||||||
turbo: 1.6.3
|
turbo: 1.6.3
|
||||||
|
|
||||||
@@ -1848,7 +1848,7 @@ packages:
|
|||||||
fs-extra: 7.0.1
|
fs-extra: 7.0.1
|
||||||
lodash.startcase: 4.4.0
|
lodash.startcase: 4.4.0
|
||||||
outdent: 0.5.0
|
outdent: 0.5.0
|
||||||
prettier: 2.7.1
|
prettier: 2.8.0
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
semver: 5.7.1
|
semver: 5.7.1
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2015,7 +2015,7 @@ packages:
|
|||||||
'@changesets/types': 5.2.0
|
'@changesets/types': 5.2.0
|
||||||
fs-extra: 7.0.1
|
fs-extra: 7.0.1
|
||||||
human-id: 1.0.2
|
human-id: 1.0.2
|
||||||
prettier: 2.7.1
|
prettier: 2.8.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@cnakazawa/watch/1.0.4:
|
/@cnakazawa/watch/1.0.4:
|
||||||
@@ -12447,6 +12447,12 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prettier/2.8.0:
|
||||||
|
resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/pretty-error/2.1.2:
|
/pretty-error/2.1.2:
|
||||||
resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==}
|
resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user