New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

remix-hook-form

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

remix-hook-form - npm Package Compare versions

Comparing version 1.2.3 to 2.0.0

dist/index.cjs

137

dist/index.d.ts

@@ -1,4 +0,133 @@

export { parseFormData, createFormData, getValidatedFormData, validateFormData, getFormDataFromSearchParams, } from "./utilities";
export * from "./hook";
export type { UseRemixFormOptions } from "./hook";
//# sourceMappingURL=index.d.ts.map
import * as react_hook_form from 'react-hook-form';
import { FieldValues, Resolver, FieldErrors, SubmitHandler, SubmitErrorHandler } from 'react-hook-form';
import React from 'react';
import { SubmitFunction, FetcherWithComponents } from '@remix-run/react';
import { FieldValues as FieldValues$1, UseFormProps, Path, RegisterOptions, UseFormReturn } from 'react-hook-form/dist/types';
declare const getFormDataFromSearchParams: (request: Pick<Request, "url">) => Record<any, any>;
/**
* Parses the data from an HTTP request and validates it against a schema. Works in both loaders and actions, in loaders it extracts the data from the search params.
* In actions it extracts it from request formData.
*
* @async
* @param {Request} request - An object that represents an HTTP request.
* @param validator - A function that resolves the schema.
* @returns A Promise that resolves to an object containing the validated data or any errors that occurred during validation.
*/
declare const getValidatedFormData: <T extends FieldValues>(request: Request, resolver: Resolver) => Promise<{
receivedValues: Record<any, any>;
errors: FieldErrors<T>;
data: undefined;
} | {
receivedValues: Record<any, any>;
errors: undefined;
data: T;
}>;
/**
* Helper method used in actions to validate the form data parsed from the frontend using zod and return a json error if validation fails.
* @param data Data to validate
* @param resolver Schema to validate and cast the data with
* @returns Returns the validated data if successful, otherwise returns the error object
*/
declare const validateFormData: <T extends FieldValues>(data: any, resolver: Resolver) => Promise<{
errors: FieldErrors<T>;
data: undefined;
} | {
errors: undefined;
data: T;
}>;
/**
Creates a new instance of FormData with the specified data and key.
@template T - The type of the data parameter. It can be any type of FieldValues.
@param {T} data - The data to be added to the FormData. It can be either an object of type FieldValues.
@param {string} [key="formData"] - The key to be used for adding the data to the FormData.
@returns {FormData} - The FormData object with the data added to it.
*/
declare const createFormData: <T extends FieldValues>(data: T, key?: string) => FormData;
/**
Parses the specified Request object's FormData to retrieve the data associated with the specified key.
@template T - The type of the data to be returned.
@param {Request} request - The Request object whose FormData is to be parsed.
@param {string} [key="formData"] - The key of the data to be retrieved from the FormData.
@returns {Promise<T>} - A promise that resolves to the data of type T.
@throws {Error} - If no data is found for the specified key, or if the retrieved data is not a string.
*/
declare const parseFormData: <T extends unknown>(request: Request, key?: string) => Promise<T>;
type SubmitFunctionOptions = Parameters<SubmitFunction>[1];
interface UseRemixFormOptions<T extends FieldValues$1> extends UseFormProps<T> {
submitHandlers?: {
onValid?: SubmitHandler<T>;
onInvalid?: SubmitErrorHandler<T>;
};
submitConfig?: SubmitFunctionOptions;
submitData?: FieldValues$1;
fetcher?: FetcherWithComponents<T>;
}
declare const useRemixForm: <T extends FieldValues$1>({ submitHandlers, submitConfig, submitData, fetcher, ...formProps }: UseRemixFormOptions<T>) => {
handleSubmit: (e?: React.BaseSyntheticEvent<object, any, any> | undefined) => Promise<void>;
register: (name: Path<T>, options?: RegisterOptions<T> | undefined) => {
defaultValue: any;
onChange: react_hook_form.ChangeHandler;
onBlur: react_hook_form.ChangeHandler;
ref: react_hook_form.RefCallBack;
name: Path<T>;
min?: string | number | undefined;
max?: string | number | undefined;
maxLength?: number | undefined;
minLength?: number | undefined;
pattern?: string | undefined;
required?: boolean | undefined;
disabled?: boolean | undefined;
};
formState: {
dirtyFields: Partial<Readonly<react_hook_form.DeepMap<react_hook_form.DeepPartial<T>, boolean>>>;
isDirty: boolean;
isSubmitSuccessful: boolean;
isSubmitted: boolean;
isSubmitting: boolean;
isValid: boolean;
isValidating: boolean;
touchedFields: Partial<Readonly<react_hook_form.DeepMap<react_hook_form.DeepPartial<T>, boolean>>>;
submitCount: number;
isLoading: boolean;
errors: Partial<react_hook_form.FieldErrorsImpl<react_hook_form.DeepRequired<T>>>;
};
watch: react_hook_form.UseFormWatch<T>;
getValues: react_hook_form.UseFormGetValues<T>;
getFieldState: react_hook_form.UseFormGetFieldState<T>;
setError: react_hook_form.UseFormSetError<T>;
clearErrors: react_hook_form.UseFormClearErrors<T>;
setValue: react_hook_form.UseFormSetValue<T>;
trigger: react_hook_form.UseFormTrigger<T>;
resetField: react_hook_form.UseFormResetField<T>;
reset: react_hook_form.UseFormReset<T>;
unregister: react_hook_form.UseFormUnregister<T>;
control: react_hook_form.Control<T, any>;
setFocus: react_hook_form.UseFormSetFocus<T>;
};
interface RemixFormProviderProps<T extends FieldValues$1> extends Omit<UseFormReturn<T>, "handleSubmit"> {
children: React.ReactNode;
handleSubmit: any;
register: any;
}
declare const RemixFormProvider: <T extends FieldValues$1>({ children, ...props }: RemixFormProviderProps<T>) => JSX.Element;
declare const useRemixFormContext: <T extends FieldValues$1>() => {
handleSubmit: (e?: React.BaseSyntheticEvent<object, any, any> | undefined) => Promise<void>;
watch: react_hook_form.UseFormWatch<T>;
getValues: react_hook_form.UseFormGetValues<T>;
getFieldState: react_hook_form.UseFormGetFieldState<T>;
setError: react_hook_form.UseFormSetError<T>;
clearErrors: react_hook_form.UseFormClearErrors<T>;
setValue: react_hook_form.UseFormSetValue<T>;
trigger: react_hook_form.UseFormTrigger<T>;
formState: react_hook_form.FormState<T>;
resetField: react_hook_form.UseFormResetField<T>;
reset: react_hook_form.UseFormReset<T>;
unregister: react_hook_form.UseFormUnregister<T>;
control: react_hook_form.Control<T, any>;
register: react_hook_form.UseFormRegister<T>;
setFocus: react_hook_form.UseFormSetFocus<T>;
};
export { RemixFormProvider, SubmitFunctionOptions, UseRemixFormOptions, createFormData, getFormDataFromSearchParams, getValidatedFormData, parseFormData, useRemixForm, useRemixFormContext, validateFormData };

255

dist/index.js

@@ -1,95 +0,196 @@

import J from "react";
import { useSubmit as L, useActionData as U, useNavigation as K } from "@remix-run/react";
import { useForm as T, FormProvider as z, useFormContext as B } from "react-hook-form";
const g = (t) => {
const a = {};
for (const [i, o] of t.entries()) {
const n = i.split(".");
let e = a;
for (let s = 0; s < n.length - 1; s++) {
const c = n[s];
e[c] || (e[c] = /^\d+$/.test(n[s + 1]) ? [] : {}), e = e[c];
// src/utilities/index.ts
var generateFormData = (formData) => {
const outputObject = {};
for (const [key, value] of formData.entries()) {
const keyParts = key.split(".");
let currentObject = outputObject;
for (let i = 0; i < keyParts.length - 1; i++) {
const keyPart = keyParts[i];
if (!currentObject[keyPart]) {
currentObject[keyPart] = /^\d+$/.test(keyParts[i + 1]) ? [] : {};
}
currentObject = currentObject[keyPart];
}
const r = n[n.length - 1], l = /\[\d*\]$|\[\]$/.test(r);
if (l) {
const s = r.replace(/\[\d*\]$|\[\]$/, "");
e[s] || (e[s] = []), e[s].push(o);
const lastKeyPart = keyParts[keyParts.length - 1];
const lastKeyPartIsArray = /\[\d*\]$|\[\]$/.test(lastKeyPart);
if (lastKeyPartIsArray) {
const key2 = lastKeyPart.replace(/\[\d*\]$|\[\]$/, "");
if (!currentObject[key2]) {
currentObject[key2] = [];
}
currentObject[key2].push(value);
}
l || (/^\d+$/.test(r) ? e.push(o) : e[r] = o);
if (!lastKeyPartIsArray) {
if (/^\d+$/.test(lastKeyPart)) {
currentObject.push(value);
} else {
currentObject[lastKeyPart] = value;
}
}
}
return a;
}, M = (t) => {
const a = new URL(t.url).searchParams;
return g(a);
}, Q = (t) => t.method === "GET" || t.method === "get", tt = async (t, a) => {
const i = Q(t) ? M(t) : await Y(t);
return { ...await W(i, a), receivedValues: i };
}, W = async (t, a) => {
const { errors: i, values: o } = await a(t, {}, { shouldUseNativeValidation: !1, fields: {} });
return Object.keys(i).length > 0 ? { errors: i, data: void 0 } : { errors: void 0, data: o };
}, X = (t, a = "formData") => {
const i = new FormData(), o = JSON.stringify(t);
return i.append(a, o), i;
}, Y = async (t, a = "formData") => {
const i = await t.formData(), o = i.get(a);
if (!o)
return g(i);
if (typeof o != "string")
return outputObject;
};
var getFormDataFromSearchParams = (request) => {
const searchParams = new URL(request.url).searchParams;
return generateFormData(searchParams);
};
var isGet = (request) => request.method === "GET" || request.method === "get";
var getValidatedFormData = async (request, resolver) => {
const data = isGet(request) ? getFormDataFromSearchParams(request) : await parseFormData(request);
const validatedOutput = await validateFormData(data, resolver);
return { ...validatedOutput, receivedValues: data };
};
var validateFormData = async (data, resolver) => {
const { errors, values } = await resolver(
data,
{},
{ shouldUseNativeValidation: false, fields: {} }
);
if (Object.keys(errors).length > 0) {
return { errors, data: void 0 };
}
return { errors: void 0, data: values };
};
var createFormData = (data, key = "formData") => {
const formData = new FormData();
const finalData = JSON.stringify(data);
formData.append(key, finalData);
return formData;
};
var parseFormData = async (request, key = "formData") => {
const formData = await request.formData();
const data = formData.get(key);
if (!data) {
return generateFormData(formData);
}
if (!(typeof data === "string")) {
throw new Error("Data is not a string");
return JSON.parse(o);
}, S = (t, a, i = [], o = 0) => {
if (!a)
return t;
for (const [n, e] of Object.entries(a))
!i.includes(n.toString()) && i.length && o === 0 || (typeof e == "object" && !Array.isArray(e) ? (t[n] || (t[n] = {}), S(t[n], e, i, o + 1)) : e && (t[n] = e));
return t;
}, ot = ({ submitHandlers: t, submitConfig: a, submitData: i, fetcher: o, ...n }) => {
var e, r, l, s;
const c = L(), y = U(), b = (e = o == null ? void 0 : o.submit) !== null && e !== void 0 ? e : c, u = (r = o == null ? void 0 : o.data) !== null && r !== void 0 ? r : y, d = T(n), p = K().state !== "idle" || o && o.state !== "idle", D = (m) => {
b(X({ ...m, ...i }), {
}
return JSON.parse(data);
};
var mergeErrors = (frontendErrors, backendErrors, validKeys = [], depth = 0) => {
if (!backendErrors) {
return frontendErrors;
}
for (const [key, rightValue] of Object.entries(backendErrors)) {
if (!validKeys.includes(key.toString()) && validKeys.length && depth === 0) {
continue;
}
if (typeof rightValue === "object" && !Array.isArray(rightValue)) {
if (!frontendErrors[key]) {
frontendErrors[key] = {};
}
mergeErrors(frontendErrors[key], rightValue, validKeys, depth + 1);
} else if (rightValue) {
frontendErrors[key] = rightValue;
}
}
return frontendErrors;
};
// src/hook/index.tsx
import React from "react";
import {
useActionData,
useSubmit,
useNavigation
} from "@remix-run/react";
import {
useFormContext
} from "react-hook-form";
import { useForm, FormProvider } from "react-hook-form";
var useRemixForm = ({
submitHandlers,
submitConfig,
submitData,
fetcher,
...formProps
}) => {
var _a, _b, _c, _d;
const actionSubmit = useSubmit();
const actionData = useActionData();
const submit = (_a = fetcher == null ? void 0 : fetcher.submit) != null ? _a : actionSubmit;
const data = (_b = fetcher == null ? void 0 : fetcher.data) != null ? _b : actionData;
const methods = useForm(formProps);
const navigation = useNavigation();
const isSubmittingForm = navigation.state !== "idle" || fetcher && fetcher.state !== "idle";
const onSubmit = (data2) => {
submit(createFormData({ ...data2, ...submitData }), {
method: "post",
...a
...submitConfig
});
}, F = d.getValues(), h = Object.keys(F), V = () => {
}, O = d.formState, { dirtyFields: P, isDirty: w, isSubmitSuccessful: j, isSubmitted: k, isSubmitting: x, isValid: _, isValidating: $, touchedFields: R, submitCount: A, errors: N, isLoading: C } = O, I = S(N, u != null && u.errors ? u.errors : u, h);
};
const values = methods.getValues();
const validKeys = Object.keys(values);
const onInvalid = () => {
};
const formState = methods.formState;
const {
dirtyFields,
isDirty,
isSubmitSuccessful,
isSubmitted,
isSubmitting,
isValid,
isValidating,
touchedFields,
submitCount,
errors,
isLoading
} = formState;
const formErrors = mergeErrors(
errors,
(data == null ? void 0 : data.errors) ? data.errors : data,
validKeys
);
return {
...d,
handleSubmit: d.handleSubmit((l = t == null ? void 0 : t.onValid) !== null && l !== void 0 ? l : D, (s = t == null ? void 0 : t.onInvalid) !== null && s !== void 0 ? s : V),
register: (m, G) => {
var v, f;
...methods,
handleSubmit: methods.handleSubmit(
(_c = submitHandlers == null ? void 0 : submitHandlers.onValid) != null ? _c : onSubmit,
(_d = submitHandlers == null ? void 0 : submitHandlers.onInvalid) != null ? _d : onInvalid
),
register: (name, options) => {
var _a2, _b2;
return {
...d.register(m, G),
defaultValue: (f = (v = u == null ? void 0 : u.defaultValues) === null || v === void 0 ? void 0 : v[m]) !== null && f !== void 0 ? f : ""
...methods.register(name, options),
defaultValue: (_b2 = (_a2 = data == null ? void 0 : data.defaultValues) == null ? void 0 : _a2[name]) != null ? _b2 : ""
};
},
formState: {
dirtyFields: P,
isDirty: w,
isSubmitSuccessful: j,
isSubmitted: k,
isSubmitting: p || x,
isValid: _,
isValidating: $,
touchedFields: R,
submitCount: A,
isLoading: C,
errors: I
dirtyFields,
isDirty,
isSubmitSuccessful,
isSubmitted,
isSubmitting: isSubmittingForm || isSubmitting,
isValid,
isValidating,
touchedFields,
submitCount,
isLoading,
errors: formErrors
}
};
}, at = ({ children: t, ...a }) => J.createElement(z, { ...a }, t), it = () => {
const t = B();
};
var RemixFormProvider = ({
children,
...props
}) => {
return /* @__PURE__ */ React.createElement(FormProvider, { ...props }, children);
};
var useRemixFormContext = () => {
const methods = useFormContext();
return {
...t,
handleSubmit: t.handleSubmit
...methods,
handleSubmit: methods.handleSubmit
};
};
export {
at as RemixFormProvider,
X as createFormData,
M as getFormDataFromSearchParams,
tt as getValidatedFormData,
Y as parseFormData,
ot as useRemixForm,
it as useRemixFormContext,
W as validateFormData
RemixFormProvider,
createFormData,
getFormDataFromSearchParams,
getValidatedFormData,
parseFormData,
useRemixForm,
useRemixFormContext,
validateFormData
};
{
"name": "remix-hook-form",
"version": "1.2.3",
"version": "2.0.0",
"description": "Utility wrapper around react-hook-form for use with Remix.run",
"type": "module",
"main": "./dist/index.umd.cjs",
"main": "./dist/index.cjs",
"module": "./dist/index.js",

@@ -11,3 +11,3 @@ "exports": {

"import": "./dist/index.js",
"require": "./dist/index.umd.cjs"
"require": "./dist/index.cjs"
}

@@ -24,8 +24,9 @@ },

"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
"remix-dev": "npm run dev -w src/testing-app",
"build:dev": "vite build -m development",
"dev": "npm-run-all -s build:dev -p remix-dev vite",
"vite": "vite build --watch -m development",
"prepublishOnly": "vite build",
"build": "vite build",
"build:dev": "npm run build",
"build:dev:watch": "npm run build -- --watch",
"dev": "npm-run-all -s build:dev -p remix-dev build:dev:watch",
"vite": "npm run build --watch -m development",
"prepublishOnly": "npm run build",
"test": "vitest run",

@@ -83,2 +84,3 @@ "tsc": "tsc",

"rollup-plugin-typescript2": "^0.34.1",
"tsup": "^7.2.0",
"typescript": "^5.0.4",

@@ -89,2 +91,2 @@ "vite": "^4.2.1",

}
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc