mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-09 15:22:32 -06:00
Add Input Types: Checkbox, Email, Number, Password, Phone, Radio, Search, Url | Add validations: accepted, email, url
This commit is contained in:
5
.changeset/rare-birds-tickle.md
Normal file
5
.changeset/rare-birds-tickle.md
Normal file
@@ -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 { Text, Textarea } from "..";
|
||||
import { Form } from "./Form";
|
||||
import { Text, Textarea } from "./Inputs";
|
||||
|
||||
interface OnSubmitProps {
|
||||
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 { useEffectUpdateSchema } from "../../lib/schema";
|
||||
import { SVGComponent, UniversalInputProps } from "../../types";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import clsx from "clsx";
|
||||
import React, { useMemo } from "react";
|
||||
import { 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 { getValidationRules, validate } from "../../lib/validation";
|
||||
import { NameRequired, OptionsArray, OptionsObjectArray, UniversalInputProps } from "../../types";
|
||||
import { Fieldset } from "../shared/Fieldset";
|
||||
import { Help } from "../shared/Help";
|
||||
@@ -48,6 +48,7 @@ export function Checkbox(props: FormbricksProps) {
|
||||
id={elemId}
|
||||
{...register(props.name, {
|
||||
required: { value: "required" in validationRules, message: "This field is required" },
|
||||
validate: validate(validationRules),
|
||||
})}
|
||||
/>
|
||||
<Label label={props.label} elemId={elemId} />
|
||||
@@ -66,7 +67,7 @@ export function Checkbox(props: FormbricksProps) {
|
||||
<Help help={props.help} elemId={elemId} />
|
||||
<Options optionsClassName={props.optionsClassName}>
|
||||
{options.map((option) => (
|
||||
<Option optionClassName={props.optionClassName}>
|
||||
<Option key={`${props.name}-${option.value}`} optionClassName={props.optionClassName}>
|
||||
<Wrapper wrapperClassName={props.wrapperClassName}>
|
||||
<Inner innerClassName={props.innerClassName}>
|
||||
<input
|
||||
|
||||
23
packages/react/src/components/inputs/Email.tsx
Normal file
23
packages/react/src/components/inputs/Email.tsx
Normal file
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
37
packages/react/src/components/inputs/Number.tsx
Normal file
37
packages/react/src/components/inputs/Number.tsx
Normal file
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
35
packages/react/src/components/inputs/Password.tsx
Normal file
35
packages/react/src/components/inputs/Password.tsx
Normal file
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
36
packages/react/src/components/inputs/Phone.tsx
Normal file
36
packages/react/src/components/inputs/Phone.tsx
Normal file
@@ -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 React, { useMemo } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { getElementId } from "../../lib/element";
|
||||
import { normalizeOptions } from "../../lib/options";
|
||||
@@ -66,7 +66,7 @@ export function Radio(props: FormbricksProps) {
|
||||
<Help help={props.help} elemId={elemId} />
|
||||
<Options optionsClassName={props.optionsClassName}>
|
||||
{options.map((option) => (
|
||||
<Option optionClassName={props.optionClassName}>
|
||||
<Option key={`${props.name}-${option.value}`} optionClassName={props.optionClassName}>
|
||||
<Wrapper wrapperClassName={props.wrapperClassName}>
|
||||
<Inner innerClassName={props.innerClassName}>
|
||||
<input
|
||||
|
||||
35
packages/react/src/components/inputs/Search.tsx
Normal file
35
packages/react/src/components/inputs/Search.tsx
Normal file
@@ -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 { useEffectUpdateSchema } from "../../lib/schema";
|
||||
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 { getValidationRules, validate } from "../../lib/validation";
|
||||
import { NameRequired, UniversalInputProps } from "../../types";
|
||||
import { Help } from "../shared/Help";
|
||||
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";
|
||||
import { Input, InputProps } from "../shared/Input";
|
||||
|
||||
interface TextInputUniqueProps {
|
||||
maxLength?: number;
|
||||
interface TextUniqueProps {
|
||||
minLength?: number;
|
||||
maxLength?: number;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
type FormbricksProps = TextInputUniqueProps & UniversalInputProps & NameRequired;
|
||||
type Props = TextUniqueProps & InputProps & UniversalInputProps & NameRequired;
|
||||
|
||||
const inputType = "text";
|
||||
|
||||
export function Text(props: FormbricksProps) {
|
||||
const elemId = useMemo(() => getElementId(props.id, props.name), [props.id, props.name]);
|
||||
export function Text(props: Props) {
|
||||
useEffectUpdateSchema(props, inputType);
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useFormContext();
|
||||
const validationRules = getValidationRules(props.validation);
|
||||
|
||||
return (
|
||||
<Outer inputType={inputType} 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="text"
|
||||
id={elemId}
|
||||
placeholder={props.placeholder || ""}
|
||||
aria-invalid={errors[props.name] ? "true" : "false"}
|
||||
{...register(props.name, {
|
||||
required: { value: "required" in validationRules, message: "This field is required" },
|
||||
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`,
|
||||
},
|
||||
validate: validate(validationRules),
|
||||
})}
|
||||
/>
|
||||
</Inner>
|
||||
</Wrapper>
|
||||
<Help help={props.help} elemId={elemId} helpClassName={props.helpClassName} />
|
||||
<Messages {...props} />
|
||||
</Outer>
|
||||
<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 { useFormContext } from "react-hook-form";
|
||||
import { getElementId } from "../../lib/element";
|
||||
import { useEffectUpdateSchema } from "../../lib/schema";
|
||||
|
||||
35
packages/react/src/components/inputs/Url.tsx
Normal file
35
packages/react/src/components/inputs/Url.tsx
Normal file
@@ -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 React from "react";
|
||||
|
||||
interface HelpProps {
|
||||
help?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface InnerProps {
|
||||
innerClassName?: string;
|
||||
|
||||
60
packages/react/src/components/shared/Input.tsx
Normal file
60
packages/react/src/components/shared/Input.tsx
Normal file
@@ -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 React from "react";
|
||||
|
||||
interface LabelProps {
|
||||
label?: string;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface LegendProps {
|
||||
legendClassName?: string;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ErrorMessage } from "@hookform/error-message";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
interface HelpProps {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface OptionProps {
|
||||
optionClassName?: string;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface OptionsProps {
|
||||
optionsClassName?: string;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
interface OuterProps {
|
||||
inputType: string;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface WrapperProps {
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
export * from "./components/Form";
|
||||
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;
|
||||
}
|
||||
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)) {
|
||||
validationRules.required = {};
|
||||
}
|
||||
@@ -16,12 +22,27 @@ export const getValidationRules = (validation: string | undefined) => {
|
||||
if (validationRule.startsWith("min:") && !("min" in validationRules)) {
|
||||
validationRules.min = { value: validationRule.split(":")[1] };
|
||||
}
|
||||
if (validationRule === "url" && !("url" in validationRules)) {
|
||||
validationRules.url = {};
|
||||
}
|
||||
}
|
||||
return validationRules;
|
||||
};
|
||||
|
||||
export const validate = (validationRules: 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) {
|
||||
validation.max = (v: string) =>
|
||||
parseInt(v) <= validationRules.max.value ||
|
||||
@@ -36,5 +57,13 @@ export const validate = (validationRules: any) => {
|
||||
validation.number = (v: string) =>
|
||||
("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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"lib": ["ES2015", "DOM"],
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"jsx": "react",
|
||||
"jsx": "react-jsx",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
}
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -10,7 +10,7 @@ importers:
|
||||
turbo: latest
|
||||
devDependencies:
|
||||
'@changesets/cli': 2.25.0
|
||||
prettier: 2.7.1
|
||||
prettier: 2.8.0
|
||||
tsx: 3.9.0
|
||||
turbo: 1.6.3
|
||||
|
||||
@@ -1848,7 +1848,7 @@ packages:
|
||||
fs-extra: 7.0.1
|
||||
lodash.startcase: 4.4.0
|
||||
outdent: 0.5.0
|
||||
prettier: 2.7.1
|
||||
prettier: 2.8.0
|
||||
resolve-from: 5.0.0
|
||||
semver: 5.7.1
|
||||
dev: true
|
||||
@@ -2015,7 +2015,7 @@ packages:
|
||||
'@changesets/types': 5.2.0
|
||||
fs-extra: 7.0.1
|
||||
human-id: 1.0.2
|
||||
prettier: 2.7.1
|
||||
prettier: 2.8.0
|
||||
dev: true
|
||||
|
||||
/@cnakazawa/watch/1.0.4:
|
||||
@@ -12447,6 +12447,12 @@ packages:
|
||||
hasBin: 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:
|
||||
resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==}
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user