diff --git a/docs/framework/react/guides/reusable-styled-form-component.md b/docs/framework/react/guides/reusable-styled-form-component.md
new file mode 100644
index 000000000..837452f9e
--- /dev/null
+++ b/docs/framework/react/guides/reusable-styled-form-component.md
@@ -0,0 +1,321 @@
+---
+id: reusable-styled-form-component
+title: Reusable Styled Form Component
+---
+
+# Creating your own Reusable Styled Form Component
+This guide will walk you through the process of creating a reusable styled form component. A reusable styled form component is a component that encapsulates the logic and styling of a form, allowing you to reuse it across your application. It is highly opinionated and meant to be customised for your specific project. The concepts in this guide are applicable to any UI library and it is meant as a reference for you to create your own reusable styled form component.
+
+You can think of a reusable styled form component as a wrapper around TanStack Form that encapsulates the logic and styling of a form for a higher level of abstraction. It can be thought of as a giant UI component for forms that implements simpler UI components like `Input`, `Select`, `Button`, etc.
+
+## When to Create a Reusable Styled Form Component
+Creating a reusable styled form component is a great way to reduce boilerplate and enforce consistency across your application. It is especially useful if you have a lot of forms in your application, but in many cases it is overkill. If you only have a few forms in your application, it is probably better to use TanStack Form directly.
+
+## Prerequisites
+This example uses [Tailwind CSS](https://tailwindcss.com/) for styling and [Class Variance Authority](https://beta.cva.style/) for UI component variants. You can use any styling solution of your choice, just replace the custom components with your own and provide the appropriate props. It also uses `Zod` for validation, but you can use any validation library of your choice. If you want to take a look at the custom UI components you can see them in the codesandbox in the examples section.
+
+## Composition
+The reusable form component is composed of compound components to make it easier to customise. The `
` component is the main component. While ` ` and ` ` renders the appropriate components from TanStack Form. The rest of the compound components are examples of components that you can add to your own reusable form component. For example, ` ` is a compound component that renders a text field. You can add as many compound components as you want to your reusable form component and some of the examples in this guide are just that, examples. You may not need a ` ` component, but it is included here. All the components in this example are forwarding the ref to the underlying HTML element. This is so that you can access the HTML element directly if needed. For example, if you want to focus the first field in the form when the form is submitted.
+
+## Let's Get Started
+
+### ``
+
+```tsx
+const Form = React.forwardRef(
+ ({ className, children, formOptions, ...props }, ref) => {
+ const { Provider, Field, handleSubmit, useStore, Subscribe, reset } =
+ useForm({
+ validatorAdapter: zodValidator,
+ ...formOptions,
+ })
+ return (
+
+
+
+ )
+ },
+) as FormComponentProps
+```
+The `` component wraps the form in the ` ` from TanStack Form and provides the appropriate `onSubmit` props which is something you would normally do when using TanStack Form directly. It also initiates the `useForm` from Tanstack Form and here you can pass any options that you want to have in every single form in your application. For example the validator adapter. The `` component also renders the ` ` which provides the ` ` and ` ` components to the rest of the form. The `` component also provides the `useStore` hook from TanStack Form to the rest of the form. This is so that you can access the form state from anywhere in the form.
+
+### ` ` & ` `
+
+```tsx
+Form.Field = React.forwardRef(({ ...props }, ref) => {
+ const { Field } = React.useContext(FormContext)
+ return
+})
+
+Form.Subscribe = React.forwardRef(({ ...props }, ref) => {
+ const { Subscribe } = React.useContext(FormContext)
+ return
+})
+```
+The ` ` and ` ` components are just wrappers around the ` ` and ` ` components from TanStack Form. They are not necessary, but they make it easier to customise the form. For example, ` ` gives access to the `field` prop which is the field object from TanStack Form. This allows you to access and overwrite any value that you pass down in your UI compound components. For example, you can have a default `onChange={(e) => field.handleChange(e.target.value)}` prop that you want to change to something else like `onChange={(e) => field.handleChange(e.target.valueAsNumber)}` where you still would need access to the `field` prop. The ` ` component can be useful if you want to render a component that is not a field, but still needs access to the form state. For example, a loading indicator, a button that is disabled when the form is submitting, a JSON representation of the form state, etc. If you don't need this flexibility in your reusable form component, you can hardcode the ` ` and ` ` components from TanStack Form directly into your UI compound components.
+
+### ` `, ` ` & ` `
+
+```tsx
+Form.Field.Text = React.forwardRef(
+ ({ className, hasErrorField, field, label, ...props }, ref) => {
+ return (
+
+ field.handleChange(e.target.value)}
+ aria-describedby={
+ hasErrorField && field.state.meta.errors.length !== 0
+ ? `${field.name}-error`
+ : ''
+ }
+ aria-invalid={field.state.meta.errors.length !== 0}
+ ref={ref}
+ {...props}
+ />
+ {label && (
+
+ {label}
+
+ )}
+
+ )
+ },
+)
+
+Form.Field.Checkbox = React.forwardRef<
+ HTMLInputElement,
+ FormFieldCheckboxProps
+>(({ className, children, field, label, ...props }, ref) => {
+ return (
+
+ field.handleChange(e.target.checked)}
+ ref={ref}
+ {...props}
+ />
+ {label && (
+
+ {label}
+
+ )}
+
+ )
+})
+
+Form.Field.Select = React.forwardRef(
+ ({ className, hasErrorField, field, label, ...props }, ref) => {
+ return (
+
+ {label && (
+
+ {label}
+
+ )}
+ field.handleChange(e.target.value)}
+ aria-describedby={
+ hasErrorField && field.state.meta.errors.length !== 0
+ ? `${field.name}-error`
+ : ''
+ }
+ ref={ref}
+ {...props}
+ />
+
+ )
+ },
+)
+```
+The ` `, ` ` components are examples of compound components that you can add to your reusable form component. They are using the custom UI components ` `, ` `, ` ` and aswell as extra Tailwind styles to style the form. You can use your own UI components, style the primitive HTML elements directly or use a UI styling library. All of these components have all the base props that you would have to supply anyway like `id`, `name`, `value`, `onChange`, `onBlur`, etc. given through the field prop. You pass this prop from the ` ` which make it easy to overwrite anything if needed. They also optionaly render a label and error message if you pass the `label` and `hasErrorField` props. The `hasErrorField` prop is a boolean that enables aria labelling when you combine it with an error message component. This is not applicable to the Checkbox.
+
+### ` `
+
+```tsx
+Form.Field.Error = React.forwardRef(
+ ({ className, field, ...props }, ref) => {
+ return (
+ <>
+
+
+ {field.state.meta.errors.length !== 0 &&
+ field.state.meta.errors[0].split(', ')[0]}
+
+ >
+ )
+ },
+)
+```
+The ` ` component is an example of a styled error message compound component that you can combine with the other field compound components to render an error message. It shows an error message only when needed and uses aria labelling to make it accessible. It also only renders a single error message even if there are multiple errors. You can use your own error message component or style the error message directly on the field compound components. This is just an example.
+
+### ` ` & ` `
+
+```tsx
+Form.SubmitButton = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+ state.canSubmit}>
+ {(canSubmit) => (
+
+ )}
+
+ )
+ },
+)
+
+Form.ResetButton = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { reset } = React.useContext(FormContext)
+ return (
+ state.submissionAttempts}>
+ {(submissionAttempts) => (
+ reset()}
+ variant="ghost"
+ size="xs"
+ ref={ref}
+ {...props}
+ />
+ )}
+
+ )
+ },
+)
+```
+
+The ` ` and ` ` components uses a custom ` ` UI component to render the buttons with appropriate styles. They also implement the ` ` component diresctly to subscribe to the necessary form state and render the buttons accordingly. The ` ` component is disabled when the form is not ready to submit and the ` ` component is disabled when the form has not been submitted. You don't have to create these components if you dont need them. You can just use the ` ` component directly in your form if you want that, but it can be useful if you need to use the same style of Submit and Reset buttons across multiple forms. You can also choose to not implement the ` ` component directly, and instead pass the state as a prop to a ` ` component to make the prop more reusable. There is always a balance of how much abstraction you want to have in your reusable form component, and how much you want to hardcode to make it easier to customise.
+
+## A simple example
+This is a simple example of how to use this reusable styled form component as it is made here. For a more complex example, that implements many features of TanStack Form, see in the codesandbox in the example section.
+
+```tsx
+ (
+
+ )}
+ />
+ (
+
+ Porsche
+ Ferrari
+ Lamborghini
+
+ )}
+ />
+ value.includes("car"), "Must contain the word car"),
+ }}
+ children={(field) => (
+
+
+
+
+ )}
+ />
+ Submit
+ Reset
+ state.isValidating}>
+ {(isValidating) => (
+
+ {isValidating ? 'Currently validating the form' : "Not validating the form"}
+
+ )}
+
+```
+The pros with this reusable form component is that this form is not verbose at all and easy to reuse. You can also easily add new styled compound components to it and it is completely customizable. The cons is that it is more complex than just using TanStack Form directly and it is more difficult to understand how it works. It is also more difficult to debug if something goes wrong.
+
+## End Notes
+Hope this guide was helpful and that you can use it as a reference to create your own reusable styled form component, or it helped you better understand the concepts of TanStack Form. It can be smart to take a llook at the example in the codesandbox to see how it works in a more real world example.
\ No newline at end of file
diff --git a/examples/react/reusable-styled-form-component/.eslintrc.cjs b/examples/react/reusable-styled-form-component/.eslintrc.cjs
new file mode 100644
index 000000000..75ee331c1
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/.eslintrc.cjs
@@ -0,0 +1,15 @@
+// @ts-check
+
+/** @type {import('eslint').Linter.Config} */
+const config = {
+ extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: './tsconfig.json',
+ },
+ rules: {
+ 'react/no-children-prop': 'off',
+ },
+}
+
+module.exports = config
diff --git a/examples/react/reusable-styled-form-component/.gitignore b/examples/react/reusable-styled-form-component/.gitignore
new file mode 100644
index 000000000..4673b022e
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+pnpm-lock.yaml
+yarn.lock
+package-lock.json
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/examples/react/reusable-styled-form-component/README.md b/examples/react/reusable-styled-form-component/README.md
new file mode 100644
index 000000000..1cf889265
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/README.md
@@ -0,0 +1,6 @@
+# Example
+
+To run this example:
+
+- `npm install`
+- `npm run dev`
diff --git a/examples/react/reusable-styled-form-component/index.html b/examples/react/reusable-styled-form-component/index.html
new file mode 100644
index 000000000..fa8314fd9
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ TanStack Reusable Styled Form Component
+
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
diff --git a/examples/react/reusable-styled-form-component/package.json b/examples/react/reusable-styled-form-component/package.json
new file mode 100644
index 000000000..25a99976a
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "@tanstack/reusable-styled-form-component",
+ "version": "0.0.1",
+ "main": "src/index.tsx",
+ "scripts": {
+ "dev": "vite --port=3001",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@heroicons/react": "^2.1.1",
+ "@tanstack/react-form": "<1.0.0",
+ "@tanstack/zod-form-adapter": "<1.0.0",
+ "cva": "1.0.0-beta.1",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-phone-number-input": "^3.3.8",
+ "zod": "^3.21.4"
+ },
+ "devDependencies": {
+ "@tailwindcss/forms": "^0.5.7",
+ "@vitejs/plugin-react": "^4.2.1",
+ "autoprefixer": "^10.4.16",
+ "postcss": "8.4.32",
+ "tailwind-merge": "^2.2.0",
+ "tailwindcss": "^3.4.1",
+ "vite": "^5.0.10"
+ }
+}
diff --git a/examples/react/reusable-styled-form-component/postcss.config.js b/examples/react/reusable-styled-form-component/postcss.config.js
new file mode 100644
index 000000000..33ad091d2
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/examples/react/reusable-styled-form-component/src/Button.tsx b/examples/react/reusable-styled-form-component/src/Button.tsx
new file mode 100644
index 000000000..9cfb53878
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/Button.tsx
@@ -0,0 +1,22 @@
+import * as React from 'react'
+
+import { type buttonVariantProps, buttonVariants } from './variants'
+
+type ButtonProps = React.ButtonHTMLAttributes &
+ buttonVariantProps
+
+const Button = React.forwardRef(
+ ({ className, base = true, variant, size, ...props }, ref) => {
+ return (
+
+ )
+ },
+)
+
+Button.displayName = 'Button'
+
+export { Button, type ButtonProps }
diff --git a/examples/react/reusable-styled-form-component/src/Form.tsx b/examples/react/reusable-styled-form-component/src/Form.tsx
new file mode 100644
index 000000000..5cefa49f6
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/Form.tsx
@@ -0,0 +1,276 @@
+import * as React from 'react'
+import { useForm } from '@tanstack/react-form'
+import { ExclamationCircleIcon } from '@heroicons/react/20/solid'
+import { zodValidator } from '@tanstack/zod-form-adapter'
+import { cx } from './utils'
+import { Input } from './Input'
+import { Label } from './Label'
+import { Select } from './Select'
+import { Button } from './Button'
+
+type FormProps = any
+
+type FormFieldProps = any
+
+type FormFieldTextProps = any
+
+type FormFieldCheckboxProps = any
+
+type FormFieldSelectProps = any
+
+type FormFieldErrorProps = any
+
+type FormSubscribeProps = any
+
+type FormSubmitButtonProps = any
+
+type FormResetButtonProps = any
+
+type FormComponentProps = React.ForwardRefExoticComponent & {
+ Subscribe: FormSubscribeProps
+ Field: FormFieldProps & {
+ Error: React.FC
+ Text: React.FC
+ Checkbox: React.FC
+ Select: React.FC
+ }
+ SubmitButton: React.FC
+ ResetButton: React.FC
+}
+
+const FormContext = React.createContext({})
+
+const Form = React.forwardRef(
+ ({ className, children, formOptions, ...props }, ref) => {
+ const { Provider, Field, handleSubmit, useStore, Subscribe, reset } =
+ useForm({
+ validatorAdapter: zodValidator,
+ ...formOptions,
+ })
+ return (
+
+
+
+ )
+ },
+) as FormComponentProps
+
+Form.displayName = 'Form'
+
+Form.Subscribe = React.forwardRef(({ ...props }, ref) => {
+ const { Subscribe } = React.useContext(FormContext)
+ return
+})
+
+Form.Subscribe.displayName = 'Form.Subscribe'
+
+Form.Field = React.forwardRef(({ ...props }, ref) => {
+ const { Field } = React.useContext(FormContext)
+ return
+})
+
+Form.Field.displayName = 'Form.Field'
+
+Form.Field.Text = React.forwardRef(
+ ({ className, hasErrorField, field, label, ...props }, ref) => {
+ return (
+
+ field.handleChange(e.target.value)}
+ aria-describedby={
+ hasErrorField && field.state.meta.errors.length !== 0
+ ? `${field.name}-error`
+ : ''
+ }
+ aria-invalid={field.state.meta.errors.length !== 0}
+ ref={ref}
+ {...props}
+ />
+ {label && (
+
+ {label}
+
+ )}
+
+ )
+ },
+)
+
+Form.Field.Text.displayName = 'Form.Field.Text'
+
+Form.Field.Checkbox = React.forwardRef<
+ HTMLInputElement,
+ FormFieldCheckboxProps
+>(({ className, children, field, label, ...props }, ref) => {
+ return (
+
+ field.handleChange(e.target.checked)}
+ ref={ref}
+ {...props}
+ />
+ {label && (
+
+ {label}
+
+ )}
+
+ )
+})
+
+Form.Field.Checkbox.displayName = 'Form.Field.Checkbox'
+
+Form.Field.Select = React.forwardRef(
+ ({ className, hasErrorField, field, label, ...props }, ref) => {
+ return (
+
+ {label && (
+
+ {label}
+
+ )}
+ field.handleChange(e.target.value)}
+ aria-describedby={
+ hasErrorField && field.state.meta.errors.length !== 0
+ ? `${field.name}-error`
+ : ''
+ }
+ ref={ref}
+ {...props}
+ />
+
+ )
+ },
+)
+
+Form.Field.Select.displayName = 'Form.Field.Select'
+
+Form.Field.Error = React.forwardRef(
+ ({ className, field, ...props }, ref) => {
+ return (
+ <>
+
+
+ {field.state.meta.errors.length !== 0 &&
+ field.state.meta.errors[0].split(', ')[0]}
+
+ >
+ )
+ },
+)
+
+Form.Field.Error.displayName = 'Form.Field.Error'
+
+Form.SubmitButton = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+ state.canSubmit}>
+ {(canSubmit) => (
+
+ )}
+
+ )
+ },
+)
+
+Form.SubmitButton.displayName = 'Form.SubmitButton'
+
+Form.ResetButton = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ const { reset } = React.useContext(FormContext)
+ return (
+ state.submissionAttempts}>
+ {(submissionAttempts) => (
+ reset()}
+ variant="ghost"
+ size="xs"
+ ref={ref}
+ {...props}
+ />
+ )}
+
+ )
+ },
+)
+
+Form.ResetButton.displayName = 'Form.ResetButton'
+
+export {
+ Form,
+ type FormProps,
+ type FormFieldProps,
+ type FormFieldTextProps,
+ type FormFieldErrorProps,
+ type FormFieldCheckboxProps,
+ type FormFieldSelectProps,
+ type FormComponentProps,
+}
diff --git a/examples/react/reusable-styled-form-component/src/Input.tsx b/examples/react/reusable-styled-form-component/src/Input.tsx
new file mode 100644
index 000000000..3389dad32
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/Input.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react'
+import { type inputVariantProps, inputVariants } from './variants'
+
+type InputProps = React.InputHTMLAttributes &
+ Omit & {
+ invalid?: boolean
+ }
+
+const Input = React.forwardRef(
+ ({ className, type, invalid = false, ...props }, ref) => {
+ return (
+
+ )
+ },
+)
+
+Input.displayName = 'Input'
+
+export { Input, inputVariants, type InputProps }
diff --git a/examples/react/reusable-styled-form-component/src/Label.tsx b/examples/react/reusable-styled-form-component/src/Label.tsx
new file mode 100644
index 000000000..95ac71f7b
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/Label.tsx
@@ -0,0 +1,25 @@
+import * as React from 'react'
+import { cx } from './utils'
+
+type LabelProps = React.LabelHTMLAttributes & {
+ className?: string
+}
+
+const Label = React.forwardRef(
+ ({ className, ...props }, ref) => {
+ return (
+
+ )
+ },
+)
+
+Label.displayName = 'Label'
+
+export { Label, type LabelProps }
diff --git a/examples/react/reusable-styled-form-component/src/Select.tsx b/examples/react/reusable-styled-form-component/src/Select.tsx
new file mode 100644
index 000000000..cfbc46de0
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/Select.tsx
@@ -0,0 +1,73 @@
+import * as React from 'react'
+
+import { cx } from './utils'
+
+type SelectProps = React.SelectHTMLAttributes & {
+ className?: string
+ value?: string
+}
+
+type SelectOptionGroupProps = React.OptgroupHTMLAttributes
+
+type SelectOptionProps = React.OptionHTMLAttributes & {
+ value: string
+ displayValue?: string
+}
+
+type SelectComponentProps = React.ForwardRefExoticComponent & {
+ OptionGroup: React.FC
+ Option: React.FC
+}
+
+const SelectContext = React.createContext('')
+
+const Select = React.forwardRef(
+ ({ className, value, ...props }, ref) => {
+ return (
+
+
+
+ )
+ },
+) as SelectComponentProps
+
+Select.displayName = 'Select'
+
+Select.OptionGroup = React.forwardRef<
+ HTMLOptGroupElement,
+ SelectOptionGroupProps
+>(({ ...props }, ref) => {
+ return
+})
+
+Select.OptionGroup.displayName = 'Select.OptionGroup'
+
+Select.Option = React.forwardRef(
+ ({ children, value, displayValue, ...props }, ref) => {
+ const selectedValue = React.useContext(SelectContext)
+ return (
+
+ {selectedValue === value && displayValue !== undefined
+ ? displayValue
+ : children}
+
+ )
+ },
+)
+
+Select.Option.displayName = 'Select.Option'
+
+export {
+ Select,
+ type SelectProps,
+ type SelectOptionGroupProps,
+ type SelectOptionProps,
+}
diff --git a/examples/react/reusable-styled-form-component/src/index.css b/examples/react/reusable-styled-form-component/src/index.css
new file mode 100644
index 000000000..31e208af0
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/index.css
@@ -0,0 +1,14 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ input:-webkit-autofill,
+ input:-webkit-autofill:hover,
+ input:-webkit-autofill:focus,
+ input:-webkit-autofill:active {
+ -webkit-box-shadow: 0 0 0 30px theme('colors.yellow.500') inset !important;
+ box-shadow: 0 0 0 30px theme('colors.yellow.500') inset !important;
+ transition: background-color 500ms ease-in-out 0s;
+ }
+}
diff --git a/examples/react/reusable-styled-form-component/src/index.tsx b/examples/react/reusable-styled-form-component/src/index.tsx
new file mode 100644
index 000000000..02a82f27a
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/index.tsx
@@ -0,0 +1,218 @@
+import * as React from 'react'
+import { createRoot } from 'react-dom/client'
+import {
+ getCountries,
+ getCountryCallingCode,
+ isValidPhoneNumber,
+ formatPhoneNumberIntl,
+} from 'react-phone-number-input'
+import en from 'react-phone-number-input/locale/en'
+import { z } from 'zod'
+
+import { Form } from './Form'
+import { Select } from './Select'
+
+function Username({ useStore }) {
+ const submissionAttempts = useStore((state) => state.submissionAttempts)
+
+ function checkUsernameTaken(username) {
+ return new Promise((resolve, reject) => {
+ const isTaken = [
+ 'NoobMaster69',
+ 'RickAstley',
+ 'Michael',
+ 'Tanner',
+ ].includes(username)
+ if (isTaken) {
+ reject(`The username ${username} is already taken`)
+ } else {
+ resolve()
+ }
+ })
+ }
+
+ return (
+ {
+ await checkUsernameTaken(value)
+ },
+ }
+ }
+ children={(field) => (
+
+
+
+
+ )}
+ />
+ )
+}
+
+function Phone({ useStore }) {
+ const submissionAttempts = useStore((state) => state.submissionAttempts)
+ const countryCode = getCountryCallingCode(
+ useStore((state) => state.values.country),
+ )
+ return (
+
+
(
+
+
+ {getCountries().map((country) => (
+
+ {en[country]} +{getCountryCallingCode(country)}
+
+ ))}
+
+ )}
+ />
+ isValidPhoneNumber('+' + countryCode + value),
+ 'Invalid phone number',
+ ),
+ }
+ }
+ children={(field) => (
+
+
{
+ const phoneNumberValue = e.target.value.replace(
+ /[^0-9\s()+-]/g,
+ '',
+ )
+ field.handleChange(phoneNumberValue)
+ }}
+ />
+
+
+ )}
+ />
+
+ )
+}
+
+function Password({ useStore }) {
+ const submissionAttempts = useStore((state) => state.submissionAttempts)
+ const showPassword = useStore((state) => state.values.showPassword)
+ return (
+ <>
+ /[A-Z]/.test(value),
+ 'Password must include a capital letter',
+ )
+ .refine(
+ (value) => /\d/.test(value),
+ 'Password must include a number',
+ ),
+ }
+ }
+ children={(field) => (
+
+
+
+
+ )}
+ />
+ (
+
+ )}
+ />
+ >
+ )
+}
+
+export default function App() {
+ return (
+
+ )
+}
+
+const rootElement = document.getElementById('root')!
+
+createRoot(rootElement).render( )
diff --git a/examples/react/reusable-styled-form-component/src/utils.ts b/examples/react/reusable-styled-form-component/src/utils.ts
new file mode 100644
index 000000000..cf0dec80d
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/utils.ts
@@ -0,0 +1,10 @@
+import { type VariantProps, defineConfig } from 'cva';
+import { twMerge } from 'tailwind-merge';
+
+const { cva, cx, compose } = defineConfig({
+ hooks: {
+ onComplete: (className) => twMerge(className),
+ },
+});
+
+export { cva, cx, compose, type VariantProps };
diff --git a/examples/react/reusable-styled-form-component/src/variants.ts b/examples/react/reusable-styled-form-component/src/variants.ts
new file mode 100644
index 000000000..ac472b7bb
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/src/variants.ts
@@ -0,0 +1,58 @@
+import { type VariantProps, cva } from './utils'
+
+const buttonVariants = cva({
+ variants: {
+ base: {
+ true: 'relative inline-flex select-none items-center justify-center whitespace-nowrap rounded-md font-sora text-sm font-medium text-black dark:text-white transition-colors focus-visible:z-20 focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-500 disabled:pointer-events-none disabled:opacity-50',
+ },
+ variant: {
+ primary:
+ 'bg-blue-500 text-white dark:text-white transition duration-200 hover:-translate-y-1 hover:bg-blue-500/90 hover:shadow-lg hover:shadow-blue-600/90 focus-visible:-translate-y-1 focus-visible:bg-blue/90 focus-visible:shadow-lg focus-visible:shadow-blue-600/90',
+ secondary:
+ 'bg-gray-500 text-white dark:text-white transition duration-200 hover:-translate-y-1 hover:bg-gray-500/90 hover:shadow-lg hover:shadow-gray-600/90 focus-visible:-translate-y-1 focus-visible:bg-gray-500/90 focus-visible:shadow-lg focus-visible:shadow-gray-600/90',
+ outline:
+ 'border border-gray-300 bg-white dark:bg-black hover:bg-accent/50 focus-visible:bg-accent/50 dark:border-gray-700',
+ ghost:
+ 'hover:bg-gray-200 focus-visible:bg-gray-200 hover:dark:bg-gray-800 focus-visible:dark:bg-gray-800',
+ opacity:
+ 'opacity-75 transition-opacity hover:opacity-100 focus-visible:opacity-100',
+ link: 'underline-offset-4 hover:underline',
+ },
+ size: {
+ xs: 'h-6 px-2.5',
+ sm: 'h-8 p-1',
+ md: 'h-10 px-4 py-2',
+ icon: 'h-10 w-10',
+ },
+ },
+})
+
+type buttonVariantProps = VariantProps
+
+const inputVariants = cva({
+ base: 'peer select-none appearance-none border focus:ring-0 focus:ring-offset-0 border-gray-300 transition-colors focus-visible:border-blue-500 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 focus-visible:dark:border-blue-500',
+ variants: {
+ type: {
+ text: 'flex h-10 w-full rounded-md bg-white dark:bg-black px-3 py-2 text-sm placeholder:text-gray-500',
+ password:
+ 'flex h-10 w-full rounded-md bg-white dark:bg-black px-3 py-2 text-sm placeholder:text-gray-500',
+ tel: 'flex h-10 w-full rounded-md bg-white dark:bg-black px-3 py-2 text-sm placeholder:text-gray-500',
+ checkbox:
+ 'h-4 w-4 cursor-pointer rounded-sm bg-white dark:bg-black transition-colors checked:border-blue-500 checked:bg-blue-500 checked:hover:bg-blue-500 checked:focus:bg-blue-500 checked:dark:border-blue-500',
+ number:
+ 'flex h-10 w-full rounded-md bg-white dark:bg-black px-3 py-2 text-sm [appearance:textfield] placeholder:text-gray-500 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',
+ },
+ invalid: {
+ true: 'border-red-500 focus-visible:border-red-500 dark:border-red-500 focus-visible:dark:border-red-500',
+ },
+ },
+})
+
+type inputVariantProps = VariantProps
+
+export {
+ buttonVariants,
+ inputVariants,
+ type buttonVariantProps,
+ type inputVariantProps,
+}
diff --git a/examples/react/reusable-styled-form-component/tailwind.config.js b/examples/react/reusable-styled-form-component/tailwind.config.js
new file mode 100644
index 000000000..6639a949d
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./index.html', './src/**/*.{tsx,ts}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [require('@tailwindcss/forms')],
+}
diff --git a/examples/react/reusable-styled-form-component/tsconfig.json b/examples/react/reusable-styled-form-component/tsconfig.json
new file mode 100644
index 000000000..666a0ea71
--- /dev/null
+++ b/examples/react/reusable-styled-form-component/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "noEmit": true,
+ "strict": true,
+ "esModuleInterop": true,
+ "lib": ["DOM", "DOM.Iterable", "ES2020"]
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c1ac2f11d..887cb275d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -61,7 +61,7 @@ importers:
version: 3.6.1(@typescript-eslint/parser@6.4.1)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
eslint-plugin-import:
specifier: ^2.29.1
- version: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ version: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0)
eslint-plugin-react:
specifier: ^7.33.2
version: 7.33.2(eslint@8.56.0)
@@ -148,6 +148,55 @@ importers:
specifier: ^5
version: 5.2.2
+ examples/react/reusable-styled-form-component:
+ dependencies:
+ '@heroicons/react':
+ specifier: ^2.1.1
+ version: 2.1.1(react@18.2.0)
+ '@tanstack/react-form':
+ specifier: <1.0.0
+ version: link:../../../packages/react-form
+ '@tanstack/zod-form-adapter':
+ specifier: <1.0.0
+ version: link:../../../packages/zod-form-adapter
+ cva:
+ specifier: 1.0.0-beta.1
+ version: 1.0.0-beta.1
+ react:
+ specifier: ^18.0.0
+ version: 18.2.0
+ react-dom:
+ specifier: ^18.0.0
+ version: 18.2.0(react@18.2.0)
+ react-phone-number-input:
+ specifier: ^3.3.8
+ version: 3.3.9(react-dom@18.2.0)(react@18.2.0)
+ zod:
+ specifier: ^3.21.4
+ version: 3.22.4
+ devDependencies:
+ '@tailwindcss/forms':
+ specifier: ^0.5.7
+ version: 0.5.7(tailwindcss@3.4.1)
+ '@vitejs/plugin-react':
+ specifier: ^4.2.1
+ version: 4.2.1(vite@5.0.10)
+ autoprefixer:
+ specifier: ^10.4.16
+ version: 10.4.16(postcss@8.4.32)
+ postcss:
+ specifier: 8.4.32
+ version: 8.4.32
+ tailwind-merge:
+ specifier: ^2.2.0
+ version: 2.2.0
+ tailwindcss:
+ specifier: ^3.4.1
+ version: 3.4.1
+ vite:
+ specifier: ^5.0.10
+ version: 5.0.10
+
examples/react/simple:
dependencies:
'@tanstack/react-form':
@@ -634,6 +683,11 @@ packages:
resolution: {integrity: sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==}
dev: true
+ /@alloc/quick-lru@5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+ dev: true
+
/@ampproject/remapping@2.2.1:
resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
engines: {node: '>=6.0.0'}
@@ -2583,6 +2637,14 @@ packages:
'@hapi/hoek': 9.3.0
dev: false
+ /@heroicons/react@2.1.1(react@18.2.0):
+ resolution: {integrity: sha512-JyyN9Lo66kirbCMuMMRPtJxtKJoIsXKS569ebHGGRKbl8s4CtUfLnyKJxteA+vIKySocO4s1SkTkGS4xtG/yEA==}
+ peerDependencies:
+ react: '>= 16'
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/@humanwhocodes/config-array@0.11.13:
resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
engines: {node: '>=10.10.0'}
@@ -3770,6 +3832,15 @@ packages:
resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
dev: true
+ /@tailwindcss/forms@0.5.7(tailwindcss@3.4.1):
+ resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
+ dependencies:
+ mini-svg-data-uri: 1.4.4
+ tailwindcss: 3.4.1
+ dev: true
+
/@tanstack/config@0.1.8(@types/node@18.19.4)(esbuild@0.19.11)(typescript@5.2.2)(vite@5.0.10):
resolution: {integrity: sha512-PK1fMUI+iOU8nVPV8KBEa7HykN2kA7Z4In5LRxywNU77rAZ5qj5os6k+mmGtall+nQmPr0JqkCc7rkYkCCp2qA==}
engines: {node: '>=18'}
@@ -4422,7 +4493,7 @@ packages:
'@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.7)
'@types/babel__core': 7.20.5
react-refresh: 0.14.0
- vite: 5.0.10(@types/node@18.19.4)
+ vite: 5.0.10
transitivePeerDependencies:
- supports-color
dev: true
@@ -4828,12 +4899,15 @@ packages:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
- dev: false
/appdirsjs@1.2.7:
resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==}
dev: false
+ /arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ dev: true
+
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
@@ -5031,6 +5105,22 @@ packages:
when-exit: 2.1.2
dev: true
+ /autoprefixer@10.4.16(postcss@8.4.32):
+ resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+ dependencies:
+ browserslist: 4.22.2
+ caniuse-lite: 1.0.30001572
+ fraction.js: 4.3.7
+ normalize-range: 0.1.2
+ picocolors: 1.0.0
+ postcss: 8.4.32
+ postcss-value-parser: 4.2.0
+ dev: true
+
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@@ -5342,7 +5432,6 @@ packages:
/camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- dev: false
/camelcase-keys@8.0.2:
resolution: {integrity: sha512-qMKdlOfsjlezMqxkUGGMaWWs17i2HoL15tM+wtx8ld4nLrUwU58TFdvyGOz/piNP842KeO8yXvggVQSdQ828NA==}
@@ -5423,6 +5512,21 @@ packages:
get-func-name: 2.0.2
dev: true
+ /chokidar@3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
/ci-info@2.0.0:
resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
dev: false
@@ -5432,6 +5536,10 @@ packages:
engines: {node: '>=8'}
dev: false
+ /classnames@2.5.1:
+ resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
+ dev: false
+
/cli-cursor@3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
@@ -5541,6 +5649,11 @@ packages:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: false
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: true
+
/commander@9.5.0:
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
engines: {node: ^12.20.0 || >=14}
@@ -5659,6 +5772,10 @@ packages:
yaml: 1.10.2
dev: false
+ /country-flag-icons@1.5.9:
+ resolution: {integrity: sha512-9jrjv2w7kRbqNtdtMdK2j3gmDIZzd5l9L2pZiQjF9J0mUcB+NKIGDNADTDHBEp8EQtjOkCOcciJGGSOpERdXPQ==}
+ dev: false
+
/cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
dependencies:
@@ -5683,7 +5800,6 @@ packages:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
- dev: false
/cssstyle@3.0.0:
resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
@@ -5703,6 +5819,17 @@ packages:
is-git-repository: 1.1.1
dev: true
+ /cva@1.0.0-beta.1:
+ resolution: {integrity: sha512-gznFqTgERU9q4wg7jfgqtt34+RUt9S5t0xDAAEuDwQEAXEgjdDkKXpLLNjwSxsB4Ln/sqWJEH7yhE8Ny0mxd0w==}
+ peerDependencies:
+ typescript: '>= 4.5.5 < 6'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ clsx: 2.0.0
+ dev: false
+
/damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
dev: true
@@ -5905,6 +6032,10 @@ packages:
resolution: {integrity: sha512-/oD3At60ZfhgzpofJtyClNTrIACyMdRe+ih0YiHzAniN0IZnLdLpEzgR6RtGs3kowxUkTnvV/4t1FBxXMUdusQ==}
dev: true
+ /didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ dev: true
+
/diff-sequences@26.6.2:
resolution: {integrity: sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==}
engines: {node: '>= 10.14.2'}
@@ -5922,6 +6053,10 @@ packages:
path-type: 4.0.0
dev: true
+ /dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+ dev: true
+
/doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@@ -6243,7 +6378,7 @@ packages:
eslint: 8.56.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0)
eslint-plugin-react: 7.33.2(eslint@8.56.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.56.0)
@@ -6283,7 +6418,7 @@ packages:
enhanced-resolve: 5.15.0
eslint: 8.56.0
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0)
fast-glob: 3.3.1
get-tsconfig: 4.7.0
is-core-module: 2.13.1
@@ -6306,7 +6441,7 @@ packages:
enhanced-resolve: 5.15.0
eslint: 8.56.0
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0)
fast-glob: 3.3.1
get-tsconfig: 4.7.0
is-core-module: 2.13.1
@@ -6378,7 +6513,7 @@ packages:
- supports-color
dev: true
- /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
+ /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.4.1)(eslint-import-resolver-typescript@3.6.0)(eslint@8.56.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
peerDependencies:
@@ -6870,6 +7005,10 @@ packages:
mime-types: 2.1.35
dev: true
+ /fraction.js@4.3.7:
+ resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+ dev: true
+
/fresh@0.5.2:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'}
@@ -7392,6 +7531,12 @@ packages:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: true
+ /input-format@0.3.9:
+ resolution: {integrity: sha512-99Gew2huiuYpNsyZoucauy5OT3oXEoWUeINGES4SlU74eFxbtYqNO+yEP6uKFhfB0UKTvq4gOC+6/3Oskru+IQ==}
+ dependencies:
+ prop-types: 15.8.1
+ dev: false
+
/internal-slot@1.0.5:
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
engines: {node: '>= 0.4'}
@@ -7917,6 +8062,11 @@ packages:
supports-color: 8.1.1
dev: false
+ /jiti@1.21.0:
+ resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+ hasBin: true
+ dev: true
+
/jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
dev: true
@@ -8157,6 +8307,10 @@ packages:
type-check: 0.4.0
dev: true
+ /libphonenumber-js@1.10.54:
+ resolution: {integrity: sha512-P+38dUgJsmh0gzoRDoM4F5jLbyfztkU6PY6eSK6S5HwTi/LPvnwXqVCQZlAy1FxZ5c48q25QhxGQ0pq+WQcSlQ==}
+ dev: false
+
/liftoff@4.0.0:
resolution: {integrity: sha512-rMGwYF8q7g2XhG2ulBmmJgWv25qBsqRbDn5gH0+wnuyeFt7QBJlHJmtg5qEdn4pN6WVAUMgXnIxytMFRX9c1aA==}
engines: {node: '>=10.13.0'}
@@ -8171,6 +8325,16 @@ packages:
resolve: 1.22.4
dev: true
+ /lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /lilconfig@3.0.0:
+ resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
+ engines: {node: '>=14'}
+ dev: true
+
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -8758,6 +8922,11 @@ packages:
engines: {node: '>=4'}
dev: true
+ /mini-svg-data-uri@1.4.4:
+ resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
+ hasBin: true
+ dev: true
+
/minimatch@3.0.5:
resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==}
dependencies:
@@ -8842,6 +9011,14 @@ packages:
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
dev: true
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+ dev: true
+
/nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -8979,7 +9156,11 @@ packages:
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
- dev: false
+
+ /normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
/npm-bundled@2.0.1:
resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==}
@@ -9103,6 +9284,11 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
+ /object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+ dev: true
+
/object-inspect@1.12.3:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
dev: true
@@ -9468,6 +9654,11 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
+ /pify@2.3.0:
+ resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
/pify@4.0.1:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'}
@@ -9483,7 +9674,6 @@ packages:
/pirates@4.0.6:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
- dev: false
/pkg-dir@3.0.0:
resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==}
@@ -9500,6 +9690,18 @@ packages:
pathe: 1.1.1
dev: true
+ /postcss-import@15.1.0(postcss@8.4.32):
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
+ dependencies:
+ postcss: 8.4.32
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.4
+ dev: true
+
/postcss-js@4.0.1(postcss@8.4.32):
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
@@ -9508,7 +9710,23 @@ packages:
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.32
- dev: false
+
+ /postcss-load-config@4.0.2(postcss@8.4.32):
+ resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 3.0.0
+ postcss: 8.4.32
+ yaml: 2.3.4
+ dev: true
/postcss-mixins@9.0.4(postcss@8.4.32):
resolution: {integrity: sha512-XVq5jwQJDRu5M1XGkdpgASqLk37OqkH4JCFDXl/Dn7janOJjCTEKL+36cnRVy7bMtoBzALfO7bV7nTIsFnUWLA==}
@@ -9531,7 +9749,6 @@ packages:
dependencies:
postcss: 8.4.32
postcss-selector-parser: 6.0.15
- dev: false
/postcss-preset-mantine@1.12.2(postcss@8.4.32):
resolution: {integrity: sha512-a7W/lDSeMg/LeOKb/PNKp+pVzYSSxxWFHGihnwRBEGzeY0qCZnPluH5KsJMfxqbElcf5zoiXZIyElzI/0KmgjA==}
@@ -9549,7 +9766,6 @@ packages:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
- dev: false
/postcss-simple-vars@7.0.1(postcss@8.4.32):
resolution: {integrity: sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==}
@@ -9560,6 +9776,10 @@ packages:
postcss: 8.4.32
dev: false
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+ dev: true
+
/postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -9798,6 +10018,21 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
+ /react-phone-number-input@3.3.9(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-TKK8VoFWR9RfPi90j/3Rr6j/S9V8/eovqUgNNNSyD0+WtaeLTlJVWb8DD7P57eZqkLv303sL8JMiZoExwKICxw==}
+ peerDependencies:
+ react: '>=16.8'
+ react-dom: '>=16.8'
+ dependencies:
+ classnames: 2.5.1
+ country-flag-icons: 1.5.9
+ input-format: 0.3.9
+ libphonenumber-js: 1.10.54
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
/react-refresh@0.14.0:
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
engines: {node: '>=0.10.0'}
@@ -9904,6 +10139,12 @@ packages:
dependencies:
loose-envify: 1.4.0
+ /read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ dependencies:
+ pify: 2.3.0
+ dev: true
+
/read-pkg-up@9.1.0:
resolution: {integrity: sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -9942,6 +10183,13 @@ packages:
string_decoder: 1.3.0
util-deprecate: 1.0.2
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
/readline@1.3.0:
resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==}
dev: false
@@ -10741,6 +10989,20 @@ packages:
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
dev: false
+ /sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.3
+ commander: 4.1.1
+ glob: 10.3.10
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+ dev: true
+
/sudo-prompt@9.2.1:
resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==}
dev: false
@@ -10785,6 +11047,43 @@ packages:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
dev: false
+ /tailwind-merge@2.2.0:
+ resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==}
+ dependencies:
+ '@babel/runtime': 7.23.7
+ dev: true
+
+ /tailwindcss@3.4.1:
+ resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.5.3
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.3.1
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.21.0
+ lilconfig: 2.1.0
+ micromatch: 4.0.5
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.0.0
+ postcss: 8.4.32
+ postcss-import: 15.1.0(postcss@8.4.32)
+ postcss-js: 4.0.1(postcss@8.4.32)
+ postcss-load-config: 4.0.2(postcss@8.4.32)
+ postcss-nested: 6.0.1(postcss@8.4.32)
+ postcss-selector-parser: 6.0.15
+ resolve: 1.22.4
+ sucrase: 3.35.0
+ transitivePeerDependencies:
+ - ts-node
+ dev: true
+
/tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
@@ -10837,6 +11136,19 @@ packages:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+ dev: true
+
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+ dev: true
+
/throat@5.0.0:
resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==}
dev: false
@@ -11021,6 +11333,10 @@ packages:
typescript: 5.3.3
dev: true
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ dev: true
+
/tsconfig-paths@3.15.0:
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
dependencies:
@@ -11459,6 +11775,41 @@ packages:
- supports-color
dev: true
+ /vite@5.0.10:
+ resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ esbuild: 0.19.11
+ postcss: 8.4.32
+ rollup: 4.9.2
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
/vite@5.0.10(@types/node@18.19.4):
resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -11902,6 +12253,11 @@ packages:
engines: {node: '>= 14'}
dev: false
+ /yaml@2.3.4:
+ resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
+ engines: {node: '>= 14'}
+ dev: true
+
/yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}