@juantroconisf/lib 7.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/utils/types.ts
9
2
  var NextUIError = class {
10
3
  isInvalid;
@@ -26,11 +19,15 @@ function handleNestedChange({
26
19
  hasNestedValues = false
27
20
  }) {
28
21
  if (!hasNestedValues) return { ...state, [id]: value };
29
- const propertyDepth = String(id).split("."), newValues = state;
22
+ const propertyDepth = String(id).split("."), newValues = { ...state };
30
23
  let current = newValues;
31
24
  for (let i = 0; i < propertyDepth.length - 1; i++) {
32
25
  const key = propertyDepth[i];
33
- current[key] = { ...current[key] };
26
+ if (Array.isArray(current[key])) {
27
+ current[key] = [...current[key]];
28
+ } else {
29
+ current[key] = { ...current[key] };
30
+ }
34
31
  current = current[key];
35
32
  }
36
33
  current[propertyDepth[propertyDepth.length - 1]] = value;
@@ -51,7 +48,11 @@ function handleArrayItemChange({
51
48
  } else {
52
49
  let current = item;
53
50
  for (let i = 0; i < fieldDepth.length - 1; i++) {
54
- current[fieldDepth[i]] = { ...current[fieldDepth[i]] };
51
+ if (Array.isArray(current[fieldDepth[i]])) {
52
+ current[fieldDepth[i]] = [...current[fieldDepth[i]]];
53
+ } else {
54
+ current[fieldDepth[i]] = { ...current[fieldDepth[i]] };
55
+ }
55
56
  current = current[fieldDepth[i]];
56
57
  }
57
58
  current[fieldDepth[fieldDepth.length - 1]] = value;
@@ -62,141 +63,134 @@ function handleArrayItemChange({
62
63
  function getNestedValue(obj, path) {
63
64
  return path.split(".").reduce((acc, key) => acc?.[key], obj);
64
65
  }
65
- function removeCompositeKeysByPrefix(map2, prefix) {
66
- const result = new Map(map2);
67
- for (const key of map2.keys()) {
66
+ function removeCompositeKeysByPrefix(map, prefix) {
67
+ const result = new Map(map);
68
+ for (const key of map.keys()) {
68
69
  if (key.startsWith(prefix)) {
69
70
  result.delete(key);
70
71
  }
71
72
  }
72
73
  return result;
73
74
  }
74
- function setNestedValue(state, dotPath, value) {
75
- const keys = dotPath.split(".");
76
- const copy = { ...state };
77
- let current = copy;
78
- for (let i = 0; i < keys.length - 1; i++) {
79
- current[keys[i]] = { ...current[keys[i]] };
80
- current = current[keys[i]];
81
- }
82
- current[keys[keys.length - 1]] = value;
83
- return copy;
84
- }
85
- var regex = {
86
- email: /^(([^<>()\[\]\\.,;:\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,}))$/,
87
- password: /^(?!.*\s)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~`!@#$%^&*()--+={}[\]|:;"'<>,.?/_₹]).{8,24}$/
88
- };
89
- var map = {
90
- string: (val) => Boolean(val),
91
- number: (val) => String(val) !== "",
92
- object: (val) => val !== null && Object.keys(val).length > 0
93
- };
94
- var requiredValidation = (value) => Array.isArray(value) ? value.length > 0 : map[typeof value](value);
95
- var errors = {
96
- required: {
97
- validate: (val, isRequired) => !isRequired || requiredValidation(val),
98
- msg: "REQUIRED"
99
- },
100
- min: {
101
- validate: (val, min) => val >= min,
102
- msg: "VALUE_LOW"
103
- },
104
- max: {
105
- validate: (val, max) => val <= max,
106
- msg: "VALUE_HIGH"
107
- },
108
- minLength: {
109
- validate: (val = "", min) => val.length >= min,
110
- msg: "TOO_SHORT"
111
- },
112
- maxLength: {
113
- validate: (val = "", max) => val.length <= max,
114
- msg: "TOO_LONG"
115
- },
116
- pattern: {
117
- validate: (val, pattern) => new RegExp(pattern).test(val),
118
- msg: "PATTERN_INVALID"
119
- },
120
- equal: {
121
- validate: (val, comparison) => val === comparison,
122
- msg: "NOT_EQUAL"
123
- },
124
- numberIsEqual: {
125
- validate: (val, comparison) => val === comparison,
126
- msg: "NOT_EQUAL"
127
- },
128
- email: {
129
- validate: (val) => new RegExp(regex.email).test(val),
130
- msg: "INVALID_EMAIL"
131
- },
132
- password: {
133
- validate: (val) => new RegExp(regex.password).test(val),
134
- msg: "INVALID_PASSWORD"
75
+
76
+ // src/hooks/useForm.tsx
77
+ import { Form } from "@heroui/react";
78
+
79
+ // src/hooks/useComponentLang.tsx
80
+ import { setLocale } from "yup";
81
+ import { useEffect } from "react";
82
+
83
+ // src/assets/translations.ts
84
+ var translations = {
85
+ en: {
86
+ mixed: {
87
+ default: "Invalid value",
88
+ required: "This field is required",
89
+ oneOf: "Must be one of: ${values}",
90
+ notOneOf: "Cannot be any of: ${values}",
91
+ notType: "Incorrect data format",
92
+ defined: "Must be defined"
93
+ },
94
+ string: {
95
+ length: "Must be exactly ${length} characters",
96
+ min: "Must be at least ${min} characters",
97
+ max: "Must be at most ${max} characters",
98
+ matches: 'Must match: "${regex}"',
99
+ email: "Enter a valid email address",
100
+ url: "Enter a valid URL",
101
+ uuid: "Enter a valid UUID",
102
+ trim: "Remove leading/trailing spaces",
103
+ lowercase: "Must be in lowercase",
104
+ uppercase: "Must be in uppercase",
105
+ password: "Your password doesn't meet the security criteria."
106
+ },
107
+ number: {
108
+ min: "Value must be ${min} or greater",
109
+ max: "Value must be ${max} or less",
110
+ lessThan: "Must be less than ${less}",
111
+ moreThan: "Must be greater than ${more}",
112
+ positive: "Must be a positive number",
113
+ negative: "Must be a negative number",
114
+ integer: "Must be a whole number"
115
+ },
116
+ date: {
117
+ min: "Date must be after ${min}",
118
+ max: "Date must be before ${max}"
119
+ },
120
+ boolean: {
121
+ isValue: "Must be ${value}"
122
+ },
123
+ object: {
124
+ noUnknown: "Contains unknown properties"
125
+ },
126
+ array: {
127
+ min: "Must have at least ${min} items",
128
+ max: "Must have ${max} items or fewer",
129
+ length: "Must have exactly ${length} items"
130
+ }
135
131
  },
136
- custom: {
137
- validate: (_, bool) => bool,
138
- msg: "INVALID"
132
+ es: {
133
+ mixed: {
134
+ default: "Valor no v\xE1lido",
135
+ required: "Este campo es obligatorio",
136
+ oneOf: "Debe ser uno de: ${values}",
137
+ notOneOf: "No puede ser ninguno de: ${values}",
138
+ defined: "Debe estar definido",
139
+ notType: "Formato de dato incorrecto"
140
+ },
141
+ string: {
142
+ length: "Debe tener exactamente ${length} caracteres",
143
+ min: "Debe tener al menos ${min} caracteres",
144
+ max: "Debe tener como m\xE1ximo ${max} caracteres",
145
+ matches: 'Debe coincidir con: "${regex}"',
146
+ email: "Ingresa un correo electr\xF3nico v\xE1lido",
147
+ url: "Ingresa una URL v\xE1lida",
148
+ uuid: "Ingresa un UUID v\xE1lido",
149
+ trim: "No debe contener espacios al inicio o final",
150
+ lowercase: "Debe estar en min\xFAsculas",
151
+ uppercase: "Debe estar en may\xFAsculas",
152
+ password: "Tu contrase\xF1a no cumple con los requisitos de seguridad."
153
+ },
154
+ number: {
155
+ min: "Debe ser mayor o igual a ${min}",
156
+ max: "Debe ser menor o igual a ${max}",
157
+ lessThan: "Debe ser menor a ${less}",
158
+ moreThan: "Debe ser mayor a ${more}",
159
+ positive: "Debe ser un n\xFAmero positivo",
160
+ negative: "Debe ser un n\xFAmero negativo",
161
+ integer: "Debe ser un n\xFAmero entero"
162
+ },
163
+ date: {
164
+ min: "La fecha debe ser posterior a ${min}",
165
+ max: "La fecha debe ser anterior a ${max}"
166
+ },
167
+ boolean: {
168
+ isValue: "Debe ser ${value}"
169
+ },
170
+ object: {
171
+ noUnknown: "Contiene propiedades no permitidas"
172
+ },
173
+ array: {
174
+ min: "Debe tener al menos ${min} elementos",
175
+ max: "Debe tener como m\xE1ximo ${max} elementos",
176
+ length: "Debe tener ${length} elementos"
177
+ }
139
178
  }
140
179
  };
141
180
 
142
- // lang/en.json
143
- var en_default = { BIRTH_DATE: "Birth date", DAY: "Day", DAY_PLACEHOLDER: "Choose a day", MONTH: "Month", MONTH_PLACEHOLDER: "Choose a month", YEAR: "Year", YEAR_PLACEHOLDER: "Choose a year", PRICING: "Pricing", PRICING_TABLE: "Pricing table", OUR_PRICING_PLAN: "Our pricing plan", PRICING_DESCRIPTION: "Level up your experience. Discover the plan that unlocks the features you need.", VALUE_STORAGE: "{{value}} storage", GOOGLE_CALENDAR_SYNC: "Google Calendar Sync", INTERNAL_REMINDERS: "Internal reminders", WHATSAPP_AUTOMATED_REMINDERS: "WhatsApp Automated Reminders", PROFESSIONAL: "Professional", PROFESSIONAL_PLAN_DESCRIPTION: "For single doctors looking to level up their practice", DIGITAL_PRESCRIPTIONS: "Digital prescriptions", DICOM_VIEWER: "DICOM Viewer", VERIFIED_MEDICAL_CREDENTIALS: "Verified medical credentials", PATIENT_SELF_MANAGEMENT: "Patient self management", BUY_NOW: "Buy now", ORGANIZATION: "Organization", ORGANIZATION_PLAN_DESCRIPTION: "For organizations with multiple users looking to share information", UP_TO_VALUE_STORAGE: "Up to {{value}} storage", CONFIGURABLE_USER_PERMISSIONS: "Configurable user permissions", CALCULATE_PRICING: "Calculate pricing", DOCTORS: "Doctors", ASSISTANTS: "Assistants", BASIC: "Basic", BASIC_PLAN_DESCRIPTION: "For starters in the medical industry", USER: "User", TYPE_A_VALUE: "Type a value", STORAGE: "Storage", PASSWORD: "Password", PASSWORD_PLACEHOLDER: "Enter your password", REQUIRED: "Required", TOO_SHORT: "Too short", TOO_LONG: "Too long", VALUE_LOW: "Value is too low", VALUE_HIGH: "Value is too high", PATTERN_INVALID: "Pattern is not valid", INVALID_EMAIL: "Invalid email", SHOW_PASSWORD: "Show password", HIDE_PASSWORD: "Hide password", GROUP_PRICING_CALCULATOR: "Group Pricing Calculator", VERIFIED_ACCOUNT: "Verified account", VERIFIED_ACCOUNT_TEXT: "This account has been verified by Clinikos, as well as its affiliations with the following institutions", PHONE_NUMBER: "Phone number", PHONE_NUMBER_PLACEHOLDER: "Enter your phone number", SEND_MESSAGE: "Send message", BOOK_MEETING: "Book meeting", SIGN_UP: "Sign up", INVALID_PASSWORD: "Your password doesn't meet the security criteria.", NOT_EQUAL: "Values are not equal", GENDER: "Gender", FEMALE: "Female", MALE: "Male", CLOSE: "Close", MANDATORY_FIELDS_WARNING: "", INVALID_FIELDS_WARNING: "", COUNTRY: "Country", COUNTRY_PLACEHOLDER: "Select a country", STATE: "State", STATE_PLACEHOLDER: "Select a state", CITY: "City", CITY_PLACEHOLDER: "Select a city", TIMEZONE: "Timezone", TIMEZONE_PLACEHOLDER: "Selecte a timezone", NAME: "Name", OK: "Ok", PAGE_NOT_FOUND: "Page not found", PAGE_NOT_FOUND_DESCRIPTION: "The link you clicked may be broken or the page may have been removed or renamed", TODAY: "Today", WEEK: "Week", CALENDAR: "Calendar", EVENT: "Event", NO_INFORMATION: "No information", SYNC_GOOGLE_CALENDAR: "Sync Google Calendar", NO_RESULTS: "No results were found", GOOGLE_MEET: "Google Meet", LONG_TIME_AGO: "Long time ago", TOMORROW: "Tomorrow", CHOOSE_PLAN: "Choose a plan", CHOOSE_PLAN_DESCRIPTION: "Choose a plan that fits your needs!", PRIVACY_POLICY: "", OPTIONAL: "Optional", RESULTS: "Results", LOCATION: "Location", ADDRESS: "Address", ADDRESS_PLACEHOLDER: "Enter your address", COPY_TO_CLIPBOARD: "Copy to clipboard", ACTIONS: "Actions", MIN: "Minimum", MAX: "Maximum", DUE_DATE: "Due date", QUICK_SEARCH: "Quick search", MONTHLY: "Monthly", WEEKLY: "Weekly", GOOGLE_MAPS_LINK: "Google maps link", MINUTE: "Minute", MINUTES: "Minutes", HOUR: "Hour", HOURS: "Hours", VE_ID: "Identity card", ACCOUNT_VERIFIED_BY_CLINIKOS: "This account has been verified by Clinikos, as well as its affiliations with the following institutions", INBOX: "Inbox", ACCEPTED: "Accepted", DECLINED: "Declined", NEEDS_ACTION: "Needs action", OVERDUE: "Overdue", FILTER_BY: "Filter by", REFRESH: "Refresh", LOADING: "Loading", MINUTE_LEFT: "One minute left", VALUE_MINUTES_LEFT: "{{value}} minutes left", PLAY: "Play", PAUSE: "Pause", STOP: "Stop", LOAD_MORE: "Load more", BILLING: "Billing", DOCTOR: "Doctor", ASSISTANT: "Assistant", NUMBER_OF_DOCTORS: "Number of Doctors", NUMBER_OF_ASSISTANTS: "Number of Assistants", EACH_DOCTOR: "Each doctor", EACH_ASSISTANT: "Each assistant", ROLE: "Role", PAYMENT_METHODS: "Payment methods", UPGRADE: "Upgrade", TOTAL: "Total", BUY: "Buy", TYPE: "Type", RECURRENT: "Recurrent", ACCEPT: "Accept", DECLINE: "Decline", PREFERENCES: "Preferences", BOOKING: "Booking", PATTERN_NOT_VALID: "Pattern is not valid" };
144
-
145
- // lang/es.json
146
- var es_default = { BIRTH_DATE: "Fecha de nacimiento", DAY: "D\xEDa", DAY_PLACEHOLDER: "Elige un d\xEDa", MONTH: "Mes", MONTH_PLACEHOLDER: "Elige un mes", YEAR: "A\xF1o", YEAR_PLACEHOLDER: "Elige un a\xF1o", PRICING: "Precio", PRICING_TABLE: "Tabla de precios", OUR_PRICING_PLAN: "Nuestros precios", PRICING_DESCRIPTION: "Mejora tu experiencia. Descubre el plan que desbloquea las funciones que necesitas.", VALUE_STORAGE: "{{value}} almacenamiento", GOOGLE_CALENDAR_SYNC: "Google Calenar Sync", INTERNAL_REMINDERS: "Recordatorios internos", WHATSAPP_AUTOMATED_REMINDERS: "Recordatorios automatizados de WhatsApp", PROFESSIONAL: "Profesional", PROFESSIONAL_PLAN_DESCRIPTION: "Para doctores individuales que buscan elevar sus pr\xE1cticas", DIGITAL_PRESCRIPTIONS: "Recipes digitales", DICOM_VIEWER: "Visualizador DICOM", VERIFIED_MEDICAL_CREDENTIALS: "Credenciales m\xE9dicas verificadas", PATIENT_SELF_MANAGEMENT: "Auto gesti\xF3n para pacientes", BUY_NOW: "Comprar ahora", ORGANIZATION: "Organizaci\xF3n", ORGANIZATION_PLAN_DESCRIPTION: "Para organizaciones con m\xFAltiples usuarios que buscan compartir informaci\xF3n", UP_TO_VALUE_STORAGE: "Hasta {{value}} de almacenamiento", CONFIGURABLE_USER_PERMISSIONS: "Permisolog\xEDa configurable para usuarios", CALCULATE_PRICING: "Calcular precio", DOCTORS: "Doctores", ASSISTANTS: "Asistentes", BASIC: "B\xE1sico", BASIC_PLAN_DESCRIPTION: "Para iniciar en la industria m\xE9dica", USER: "Usuario", TYPE_A_VALUE: "Ingresa un valor", STORAGE: "Almacenamiento", PASSWORD: "Contrase\xF1a", PASSWORD_PLACEHOLDER: "Ingresa tu contrase\xF1a", REQUIRED: "Requerido", TOO_SHORT: "Demasiado corto", TOO_LONG: "Demasiado largo", VALUE_LOW: "El valor es muy bajo", VALUE_HIGH: "El valor es muy alto", PATTERN_INVALID: "El patr\xF3n no es v\xE1lido", INVALID_EMAIL: "Correo inv\xE1lido", SHOW_PASSWORD: "Mostrar contrase\xF1a", HIDE_PASSWORD: "Esconder contrase\xF1a", GROUP_PRICING_CALCULATOR: "Calculadora de precios grupal", VERIFIED_ACCOUNT: "Cuenta verificada", VERIFIED_ACCOUNT_TEXT: "Esta cuenta ha sido verificada por Clinikos, as\xED como sus afiliaciones con las siguientes instituciones", PHONE_NUMBER: "N\xFAmero de tel\xE9fono", PHONE_NUMBER_PLACEHOLDER: "Ingrese su n\xFAmero de tel\xE9fono", SEND_MESSAGE: "Enviar mensaje", BOOK_MEETING: "Agendar cita", SIGN_UP: "Reg\xEDstrate", INVALID_PASSWORD: "Tu contrase\xF1a no cumple con los requisitos de seguridad.", NOT_EQUAL: "Los valores no son iguales", GENDER: "G\xE9nero", FEMALE: "Femenino", MALE: "Masculino", CLOSE: "Cerrar", MANDATORY_FIELDS_WARNING: "", INVALID_FIELDS_WARNING: "", COUNTRY: "Pa\xEDs", COUNTRY_PLACEHOLDER: "Selecciona un pa\xEDs", STATE: "Estado", STATE_PLACEHOLDER: "Selecciona un estado", CITY: "Ciudad", CITY_PLACEHOLDER: "Selecciona una ciudad", TIMEZONE: "Zona horaria", TIMEZONE_PLACEHOLDER: "Selecciona una zora horaria", NAME: "Nombre", OK: "Ok", PAGE_NOT_FOUND: "P\xE1gina no encontrada", PAGE_NOT_FOUND_DESCRIPTION: "El enlace en el que hiciste click puede que est\xE9 roto o la p\xE1gina puede haber sido eliminada o renombrada", TODAY: "Hoy", WEEK: "Semana", CALENDAR: "Calendario", EVENT: "Evento", NO_INFORMATION: "Sin informaci\xF3n", SYNC_GOOGLE_CALENDAR: "Vincular Calendario de Google", NO_RESULTS: "No se encontraron resultados", GOOGLE_MEET: "Google Meet", LONG_TIME_AGO: "Hace mucho tiempo", TOMORROW: "Ma\xF1ana", CHOOSE_PLAN: "Elige un plan", CHOOSE_PLAN_DESCRIPTION: "\xA1Elige el plan que se ajuste a tus necesidades!", PRIVACY_POLICY: "", OPTIONAL: "Opcional", RESULTS: "Resultados", LOCATION: "Ubicaci\xF3n", ADDRESS: "Direcci\xF3n", ADDRESS_PLACEHOLDER: "Ingresa tu direcci\xF3n", COPY_TO_CLIPBOARD: "Copiar al portapapeles", ACTIONS: "Acciones", MIN: "M\xEDnimo", MAX: "M\xE1ximo", DUE_DATE: "Fecha l\xEDmite", QUICK_SEARCH: "B\xFAsqueda r\xE1pida", MONTHLY: "Mensual", WEEKLY: "Semanal", GOOGLE_MAPS_LINK: "Link de Google Maps", MINUTE: "Minuto", MINUTES: "Minutos", HOUR: "Hora", HOURS: "Horas", VE_ID: "C\xE9dula de Identidad", ACCOUNT_VERIFIED_BY_CLINIKOS: "Esta cuenta ha sido verificada por Clinikos, as\xED como sus afiliaciones con las siguientes instituciones", INBOX: "Bandeja de entrada", ACCEPTED: "Aceptado", DECLINED: "Declinado", NEEDS_ACTION: "Necesita acci\xF3n", OVERDUE: "Atrasado", FILTER_BY: "Filtrar por", REFRESH: "Refrescar", LOADING: "Cargando", MINUTE_LEFT: "Un minuto restante", VALUE_MINUTES_LEFT: "{{value}} minutos restantes", PLAY: "Reproducir", PAUSE: "Pausar", STOP: "Detener", LOAD_MORE: "Cargar m\xE1s", BILLING: "Facturaci\xF3n", DOCTOR: "Doctor", ASSISTANT: "Asistente", NUMBER_OF_DOCTORS: "N\xFAmero de Doctores", NUMBER_OF_ASSISTANTS: "N\xFAmero de Asistentes", EACH_DOCTOR: "Cada doctor", EACH_ASSISTANT: "Cada asistente", ROLE: "Rol", PAYMENT_METHODS: "M\xE9todos de pago", UPGRADE: "Mejorar", TOTAL: "Total", BUY: "Comprar", TYPE: "Tipo", RECURRENT: "Recurrente", ACCEPT: "Aceptar", DECLINE: "Declinar", PREFERENCES: "Preferencias", BOOKING: "Agendar cita", PATTERN_NOT_VALID: "El patr\xF3n no es v\xE1lido" };
147
-
148
181
  // src/hooks/useComponentLang.tsx
149
182
  var cookieName = "LOCALE";
150
- var langMap = {
151
- en: en_default,
152
- es: es_default
153
- };
154
183
  var getClientCookie = () => {
155
184
  const value = "; " + document.cookie, decodedValue = decodeURIComponent(value), parts = decodedValue.split("; " + cookieName + "=");
156
185
  if (parts.length === 2) return parts.pop()?.split(";").shift();
157
186
  };
158
- var getServerCookie = () => {
159
- try {
160
- const { cookies } = __require("next/headers");
161
- return cookies().get(cookieName)?.value;
162
- } catch {
163
- return "es";
164
- }
165
- };
166
187
  function useComponentLanguage() {
167
- const isServer = typeof window === "undefined", locale = (isServer ? getServerCookie() : getClientCookie()) || "en";
168
- return {
169
- locale,
170
- lang: langMap[locale]
171
- };
172
- }
173
-
174
- // src/hooks/useValidate.tsx
175
- var validProps = {
176
- isInvalid: false,
177
- errorMessage: ""
178
- };
179
- function useValidate() {
180
- const { lang } = useComponentLanguage();
181
- const performValidations = (value, validationTypes, errorMessages) => {
182
- if (!validationTypes) return validProps;
183
- const items = Object.entries(validationTypes), requiredExist = validationTypes?.required !== void 0, isRequired = requiredExist ? validationTypes.required : false;
184
- if (value === "" && !isRequired) return validProps;
185
- let errorFound = validProps;
186
- for (const [key, opts] of items) {
187
- if (opts === null) continue;
188
- const { validate, msg } = errors[key], isInvalid = !validate(value, opts);
189
- if (isInvalid) {
190
- errorFound = {
191
- isInvalid,
192
- errorMessage: errorMessages?.[key] || lang[msg]
193
- };
194
- break;
195
- }
188
+ useEffect(() => {
189
+ const locale = getClientCookie() || "en";
190
+ if (translations[locale]) {
191
+ setLocale(translations[locale]);
196
192
  }
197
- return errorFound;
198
- };
199
- return { performValidations };
193
+ }, []);
200
194
  }
201
195
 
202
196
  // src/hooks/useForm.utils.ts
@@ -240,7 +234,7 @@ function resolveFieldData(args, state, getIndex, getNestedValue2) {
240
234
  }
241
235
  const arrayKey = arg0;
242
236
  const index = arg1;
243
- const arr = state[arrayKey];
237
+ const arr = getNestedValue2(state, arrayKey);
244
238
  return {
245
239
  type: "primitiveArray" /* PrimitiveArray */,
246
240
  compositeKey: `${arrayKey}.@${index}`,
@@ -294,19 +288,42 @@ function resolveFieldData(args, state, getIndex, getNestedValue2) {
294
288
  }
295
289
 
296
290
  // src/hooks/useForm.tsx
297
- function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
298
- const [state, setState] = useState(initialState);
299
- const [touched, setTouched] = useState(/* @__PURE__ */ new Map());
300
- const [errors2, setErrors] = useState(/* @__PURE__ */ new Map());
301
- const { performValidations } = useValidate();
302
- const stateRef = useRef(state);
303
- const touchedRef = useRef(touched);
304
- const errorsRef = useRef(errors2);
291
+ import { isSchema, object, reach } from "yup";
292
+ import { jsx } from "react/jsx-runtime";
293
+ var DEFAULT_OPTIONS = {};
294
+ function useForm(schema, {
295
+ arrayIdentifiers,
296
+ onFormSubmit: onFormSubmitProp,
297
+ resetOnSubmit = false,
298
+ keepValues: keepValuesProp
299
+ } = DEFAULT_OPTIONS) {
300
+ const { initialState, validationSchema } = useMemo(() => {
301
+ const state2 = {};
302
+ const extractedRules = {};
303
+ Object.entries(schema).forEach(([key, value]) => {
304
+ if (isSchema(value)) {
305
+ try {
306
+ state2[key] = value.cast(void 0);
307
+ } catch {
308
+ state2[key] = void 0;
309
+ }
310
+ extractedRules[key] = value;
311
+ } else {
312
+ state2[key] = value;
313
+ }
314
+ });
315
+ return {
316
+ initialState: state2,
317
+ validationSchema: object().shape(extractedRules)
318
+ };
319
+ }, [schema]);
320
+ const [state, setState] = useState(initialState), [metadata, setMetadata] = useState(/* @__PURE__ */ new Map());
321
+ useComponentLanguage();
322
+ const stateRef = useRef(state), metadataRef = useRef(metadata);
305
323
  stateRef.current = state;
306
- touchedRef.current = touched;
307
- errorsRef.current = errors2;
324
+ metadataRef.current = metadata;
308
325
  const indexMap = useMemo(() => {
309
- const map2 = /* @__PURE__ */ new Map();
326
+ const map = /* @__PURE__ */ new Map();
310
327
  const traverse = (current, path) => {
311
328
  if (!current || typeof current !== "object") return;
312
329
  if (Array.isArray(current)) {
@@ -322,7 +339,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
322
339
  traverse(item, `${path}.${index}`);
323
340
  }
324
341
  });
325
- map2.set(path, itemMap);
342
+ map.set(path, itemMap);
326
343
  } else {
327
344
  Object.keys(current).forEach((key) => {
328
345
  const nextPath = path ? `${path}.${key}` : key;
@@ -331,105 +348,139 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
331
348
  }
332
349
  };
333
350
  traverse(state, "");
334
- return map2;
351
+ return map;
335
352
  }, [state, arrayIdentifiers]);
336
353
  const indexMapRef = useRef(indexMap);
337
354
  indexMapRef.current = indexMap;
338
355
  const getIndex = useCallback((arrayKey, itemId) => {
339
356
  return indexMapRef.current.get(arrayKey)?.get(itemId);
340
357
  }, []);
341
- const getRule = useCallback(
342
- (path) => {
343
- if (rules?.[path]) return rules[path];
344
- const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
345
- return rules?.[genericPath];
346
- },
347
- [rules]
348
- );
349
- const getMessage = useCallback(
350
- (path) => {
351
- if (messages?.[path]) return messages[path];
358
+ const ruleCache = useRef(/* @__PURE__ */ new Map());
359
+ useMemo(() => {
360
+ ruleCache.current.clear();
361
+ }, [validationSchema]);
362
+ const getRule = useCallback((path, schema2) => {
363
+ if (ruleCache.current.has(path)) {
364
+ return ruleCache.current.get(path);
365
+ }
366
+ let rule;
367
+ try {
368
+ rule = reach(schema2, path);
369
+ } catch {
352
370
  const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
353
- return messages?.[genericPath];
371
+ try {
372
+ rule = reach(schema2, genericPath);
373
+ } catch {
374
+ rule = void 0;
375
+ }
376
+ }
377
+ ruleCache.current.set(path, rule);
378
+ return rule;
379
+ }, []);
380
+ const runValidation = useCallback(
381
+ (ruleDef, value, compositeKey) => {
382
+ if (isSchema(ruleDef)) {
383
+ try {
384
+ ruleDef.validateSync(value);
385
+ return false;
386
+ } catch (err) {
387
+ const error = {
388
+ isInvalid: true,
389
+ errorMessage: err.message || "Invalid"
390
+ };
391
+ setMetadata((prev) => {
392
+ const newMap = new Map(prev);
393
+ const currentMeta = newMap.get(compositeKey) || {
394
+ isTouched: false,
395
+ isInvalid: false,
396
+ errorMessage: ""
397
+ };
398
+ newMap.set(compositeKey, { ...currentMeta, ...error });
399
+ return newMap;
400
+ });
401
+ return true;
402
+ }
403
+ }
404
+ return false;
354
405
  },
355
- [messages]
406
+ []
356
407
  );
357
408
  const validateField = useCallback(
358
- (compositeKey, fieldPath, value, extraContext) => {
359
- let ruleDef = getRule(fieldPath);
360
- if (!ruleDef) {
361
- const stripped = fieldPath.replace(/\.@\d+/g, "").replace(/\.@\d+$/, "");
362
- if (stripped !== fieldPath) ruleDef = getRule(stripped);
363
- }
364
- const rule = typeof ruleDef === "function" ? ruleDef(
365
- value,
366
- stateRef.current,
367
- extraContext?.item,
368
- extraContext?.index
369
- ) : ruleDef;
370
- let message = getMessage(fieldPath);
371
- if (!message && fieldPath !== fieldPath.replace(/\.@\d+/, "")) {
372
- message = getMessage(fieldPath.replace(/\.@\d+/, ""));
409
+ (compositeKey, fieldPath, value) => {
410
+ let schemaRule = getRule(fieldPath, validationSchema);
411
+ if (schemaRule) {
412
+ if (runValidation(schemaRule, value, compositeKey)) return true;
373
413
  }
374
- const error = performValidations(value, rule, message);
375
- setErrors((prev) => {
414
+ setMetadata((prev) => {
376
415
  const newMap = new Map(prev);
377
- newMap.set(compositeKey, error);
416
+ const currentMeta = newMap.get(compositeKey) || {
417
+ isTouched: false,
418
+ isInvalid: false,
419
+ errorMessage: ""
420
+ };
421
+ newMap.set(compositeKey, {
422
+ ...currentMeta,
423
+ isInvalid: false,
424
+ errorMessage: ""
425
+ });
378
426
  return newMap;
379
427
  });
380
- return error.isInvalid;
428
+ return false;
381
429
  },
382
- [getRule, getMessage, performValidations]
430
+ [getRule, runValidation, validationSchema]
383
431
  );
384
432
  const validateAll = useCallback(() => {
385
- if (!rules) return false;
386
- const nextErrors = /* @__PURE__ */ new Map();
387
- let hasInvalid = false;
388
- const processRule = (ruleKey, ruleVal) => {
389
- const isGeneric = !ruleKey.match(/\.\d+\./) && !ruleKey.match(/\.@\d+/);
390
- const parts = ruleKey.split(".");
391
- let arrayKey = "";
392
- let arrayIndexInPath = -1;
393
- for (let i = 0; i < parts.length; i++) {
394
- if (indexMapRef.current.has(parts[i])) {
395
- arrayKey = parts[i];
396
- arrayIndexInPath = i;
397
- break;
398
- }
399
- }
400
- if (arrayKey && arrayIndexInPath !== -1) {
401
- const itemMap = indexMapRef.current.get(arrayKey);
402
- if (itemMap) {
403
- itemMap.forEach((idx, itemId) => {
404
- const suffix = parts.slice(arrayIndexInPath + 1).join(".");
405
- const compositeKey = `${arrayKey}.${itemId}` + (suffix ? `.${suffix}` : "");
406
- const item = stateRef.current[arrayKey][idx];
407
- const val = getNestedValue(item, suffix);
408
- const rule = typeof ruleVal === "function" ? ruleVal(val, stateRef.current, item, idx) : ruleVal;
409
- const msg = getMessage(ruleKey);
410
- const err = performValidations(val, rule, msg);
411
- nextErrors.set(compositeKey, err);
412
- if (err.isInvalid) hasInvalid = true;
433
+ if (!validationSchema) return false;
434
+ let hasError = false;
435
+ const newMetadata = new Map(metadataRef.current);
436
+ try {
437
+ validationSchema.validateSync(state, { abortEarly: false });
438
+ } catch (err) {
439
+ hasError = true;
440
+ if (err.inner) {
441
+ err.inner.forEach((validationError) => {
442
+ const yupPath = validationError.path;
443
+ const dotPath = yupPath.replace(/\[(\d+)\]/g, ".$1");
444
+ const parts = dotPath.split(".");
445
+ let current = state;
446
+ const compositeParts = [];
447
+ for (let i = 0; i < parts.length; i++) {
448
+ const part = parts[i];
449
+ if (Array.isArray(current)) {
450
+ const index = parseInt(part, 10);
451
+ const item = current[index];
452
+ if (item && typeof item === "object") {
453
+ const genericPath = compositeParts.join(".").replace(/\.\d+/g, "");
454
+ const idKey = arrayIdentifiers?.[genericPath] || "id";
455
+ const id = item[idKey];
456
+ compositeParts.push(String(id !== void 0 ? id : index));
457
+ } else {
458
+ compositeParts.push(part);
459
+ }
460
+ current = item;
461
+ } else {
462
+ compositeParts.push(part);
463
+ current = current?.[part];
464
+ }
465
+ }
466
+ const compositeKey = compositeParts.join(".");
467
+ const currentMeta = newMetadata.get(compositeKey) || {
468
+ isTouched: false,
469
+ isInvalid: false,
470
+ errorMessage: ""
471
+ };
472
+ newMetadata.set(compositeKey, {
473
+ ...currentMeta,
474
+ isTouched: true,
475
+ isInvalid: true,
476
+ errorMessage: validationError.message
413
477
  });
414
- }
415
- } else {
416
- const val = getNestedValue(stateRef.current, ruleKey);
417
- const rule = typeof ruleVal === "function" ? ruleVal(val, stateRef.current) : ruleVal;
418
- const msg = getMessage(ruleKey);
419
- const err = performValidations(val, rule, msg);
420
- nextErrors.set(ruleKey, err);
421
- if (err.isInvalid) hasInvalid = true;
478
+ });
422
479
  }
423
- };
424
- Object.entries(rules).forEach(([k, v]) => processRule(k, v));
425
- setErrors(nextErrors);
426
- setTouched((prev) => {
427
- const next = new Map(prev);
428
- nextErrors.forEach((_, k) => next.set(k, true));
429
- return next;
430
- });
431
- return hasInvalid;
432
- }, [rules, getMessage, performValidations]);
480
+ }
481
+ setMetadata(newMetadata);
482
+ return hasError;
483
+ }, [validationSchema, state, arrayIdentifiers]);
433
484
  const handleFieldChange = useCallback(
434
485
  (resolution, newValue) => {
435
486
  if (!resolution) return;
@@ -443,18 +494,33 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
443
494
  parentId,
444
495
  nestedField
445
496
  } = resolution;
497
+ let finalValue = newValue;
498
+ let rule = getRule(fieldPath, validationSchema);
499
+ if (rule && rule.type === "array" && type === "primitiveArray" /* PrimitiveArray */ && rule.innerType) {
500
+ rule = rule.innerType;
501
+ }
502
+ if (rule && rule.type === "string") {
503
+ try {
504
+ finalValue = rule.cast(newValue);
505
+ } catch {
506
+ }
507
+ }
446
508
  setState((prev) => {
447
509
  if (type === "scalar" /* Scalar */) {
448
510
  return handleNestedChange({
449
511
  state: prev,
450
512
  id: compositeKey,
451
- value: newValue
513
+ value: finalValue,
514
+ hasNestedValues: compositeKey.includes(".")
452
515
  });
453
516
  }
454
517
  if (type === "primitiveArray" /* PrimitiveArray */) {
455
- const arr = [...prev[arrayKey]];
456
- arr[index] = newValue;
457
- return { ...prev, [arrayKey]: arr };
518
+ return handleNestedChange({
519
+ state: prev,
520
+ id: `${arrayKey}.${index}`,
521
+ value: finalValue,
522
+ hasNestedValues: true
523
+ });
458
524
  }
459
525
  if (type === "objectArray" /* ObjectArray */) {
460
526
  return handleArrayItemChange({
@@ -462,7 +528,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
462
528
  arrayKey,
463
529
  index,
464
530
  field: resolution.field,
465
- value: newValue
531
+ value: finalValue
466
532
  });
467
533
  }
468
534
  if (type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
@@ -471,41 +537,40 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
471
537
  const parentArr = [...prev[parentKey]];
472
538
  const pItem = { ...parentArr[pIndex] };
473
539
  const nestedArr = [...getNestedValue(pItem, nestedField) || []];
474
- nestedArr[index] = newValue;
540
+ nestedArr[index] = finalValue;
475
541
  pItem[nestedField] = nestedArr;
476
- const updatedItem = setNestedValue(pItem, nestedField, nestedArr);
477
- parentArr[pIndex] = updatedItem;
542
+ parentArr[pIndex] = pItem;
478
543
  return { ...prev, [parentKey]: parentArr };
479
544
  }
480
545
  return prev;
481
546
  });
482
- let extraContext = {};
483
- if (type === "objectArray" /* ObjectArray */ || type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
484
- const idx = index;
485
- const arrKey = arrayKey || parentKey;
486
- extraContext = {
487
- index: idx,
488
- item: stateRef.current[arrKey]?.[idx]
489
- };
490
- }
491
- validateField(compositeKey, fieldPath, newValue, extraContext);
547
+ validateField(compositeKey, fieldPath, finalValue);
492
548
  },
493
- [getIndex, validateField]
549
+ [getIndex, validateField, getRule, validationSchema]
494
550
  );
495
551
  const createHandlers = useCallback(
496
552
  (resolution) => {
497
553
  if (!resolution) return {};
498
554
  const { compositeKey, fieldPath, value } = resolution;
499
- const err = errorsRef.current.get(compositeKey);
500
- const isTouched = touchedRef.current.get(compositeKey);
555
+ const meta = metadataRef.current.get(compositeKey);
556
+ const isTouched = meta?.isTouched;
501
557
  return {
502
558
  id: compositeKey,
503
- isInvalid: Boolean(isTouched && err?.isInvalid),
504
- errorMessage: isTouched ? err?.errorMessage || "" : "",
559
+ isInvalid: Boolean(isTouched && meta?.isInvalid),
560
+ errorMessage: isTouched ? meta?.errorMessage || "" : "",
505
561
  onBlur: () => {
506
- if (touchedRef.current.get(compositeKey)) return;
562
+ if (metadataRef.current.get(compositeKey)?.isTouched) return;
507
563
  validateField(compositeKey, fieldPath, value);
508
- setTouched((prev) => new Map(prev).set(compositeKey, true));
564
+ setMetadata((prev) => {
565
+ const newMap = new Map(prev);
566
+ const current = newMap.get(compositeKey) || {
567
+ isTouched: false,
568
+ isInvalid: false,
569
+ errorMessage: ""
570
+ };
571
+ newMap.set(compositeKey, { ...current, isTouched: true });
572
+ return newMap;
573
+ });
509
574
  }
510
575
  };
511
576
  },
@@ -569,54 +634,77 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
569
634
  () => ({
570
635
  addItem: (arrayKey, item, index) => {
571
636
  setState((prev) => {
572
- const arr = [...prev[arrayKey]];
637
+ const arr = [...getNestedValue(prev, arrayKey) || []];
573
638
  if (index === void 0) arr.push(item);
574
639
  else arr.splice(index, 0, item);
575
- return { ...prev, [arrayKey]: arr };
640
+ return handleNestedChange({
641
+ state: prev,
642
+ id: arrayKey,
643
+ value: arr,
644
+ hasNestedValues: String(arrayKey).includes(".")
645
+ });
576
646
  });
577
647
  },
578
648
  removeItem: (arrayKey, index) => {
579
- const currentArr = stateRef.current[arrayKey];
649
+ const currentArr = getNestedValue(stateRef.current, arrayKey) || [];
580
650
  const item = currentArr[index];
581
651
  const idKey = arrayIdentifiers?.[arrayKey] || "id";
582
652
  const itemId = item?.[idKey];
583
653
  setState((prev) => {
584
- const arr = [...prev[arrayKey]];
654
+ const arr = [...getNestedValue(prev, arrayKey) || []];
585
655
  arr.splice(index, 1);
586
- return { ...prev, [arrayKey]: arr };
656
+ return handleNestedChange({
657
+ state: prev,
658
+ id: arrayKey,
659
+ value: arr,
660
+ hasNestedValues: String(arrayKey).includes(".")
661
+ });
587
662
  });
588
663
  if (itemId !== void 0) {
589
664
  const prefix = `${String(arrayKey)}.${itemId}.`;
590
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
591
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
665
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
592
666
  }
593
667
  },
594
668
  removeById: (arrayKey, itemId) => {
595
669
  const index = getIndex(arrayKey, itemId);
596
670
  if (index !== void 0) {
597
671
  setState((prev) => {
598
- const arr = [...prev[arrayKey]];
672
+ const arr = [...getNestedValue(prev, arrayKey) || []];
599
673
  arr.splice(index, 1);
600
- return { ...prev, [arrayKey]: arr };
674
+ return handleNestedChange({
675
+ state: prev,
676
+ id: arrayKey,
677
+ value: arr,
678
+ hasNestedValues: String(arrayKey).includes(".")
679
+ });
601
680
  });
602
681
  const prefix = `${String(arrayKey)}.${itemId}.`;
603
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
604
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
682
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
605
683
  }
606
684
  },
607
685
  updateItem: (arrayKey, index, value) => {
608
686
  setState((prev) => {
609
- const arr = [...prev[arrayKey]];
687
+ const arr = [...getNestedValue(prev, arrayKey) || []];
610
688
  arr[index] = value;
611
- return { ...prev, [arrayKey]: arr };
689
+ return handleNestedChange({
690
+ state: prev,
691
+ id: arrayKey,
692
+ value: arr,
693
+ hasNestedValues: String(arrayKey).includes(".")
694
+ });
612
695
  });
613
696
  },
614
697
  moveItem: (arrayKey, from, to) => {
615
698
  setState((prev) => {
616
- const arr = [...prev[arrayKey]];
699
+ const arr = [...getNestedValue(prev, arrayKey) || []];
617
700
  const [item] = arr.splice(from, 1);
618
701
  arr.splice(to, 0, item);
619
- return { ...prev, [arrayKey]: arr };
702
+ return handleNestedChange({
703
+ state: prev,
704
+ id: arrayKey,
705
+ value: arr,
706
+ hasNestedValues: String(arrayKey).includes(".")
707
+ });
620
708
  });
621
709
  },
622
710
  moveById: (arrayKey, fromId, toId) => {
@@ -624,25 +712,42 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
624
712
  const toIndex = getIndex(arrayKey, toId);
625
713
  if (fromIndex !== void 0 && toIndex !== void 0) {
626
714
  setState((prev) => {
627
- const arr = [...prev[arrayKey]];
715
+ const arr = [...getNestedValue(prev, arrayKey) || []];
628
716
  const [item] = arr.splice(fromIndex, 1);
629
717
  arr.splice(toIndex, 0, item);
630
- return { ...prev, [arrayKey]: arr };
718
+ return handleNestedChange({
719
+ state: prev,
720
+ id: arrayKey,
721
+ value: arr,
722
+ hasNestedValues: String(arrayKey).includes(".")
723
+ });
631
724
  });
632
725
  }
633
726
  },
634
727
  getItem: (arrayKey, itemId) => {
635
728
  const index = getIndex(arrayKey, itemId);
636
729
  if (index === void 0) return void 0;
637
- return stateRef.current[arrayKey][index];
730
+ return getNestedValue(stateRef.current, arrayKey)[index];
638
731
  }
639
732
  }),
640
733
  [getIndex, arrayIdentifiers]
641
734
  );
642
- const onBlur = (id) => {
643
- validateField(String(id), String(id), stateRef.current[id]);
644
- setTouched((prev) => new Map(prev).set(String(id), true));
645
- };
735
+ const onBlur = useCallback(
736
+ (id) => {
737
+ validateField(String(id), String(id), stateRef.current[id]);
738
+ setMetadata((prev) => {
739
+ const newMap = new Map(prev);
740
+ const current = newMap.get(String(id)) || {
741
+ isTouched: false,
742
+ isInvalid: false,
743
+ errorMessage: ""
744
+ };
745
+ newMap.set(String(id), { ...current, isTouched: true });
746
+ return newMap;
747
+ });
748
+ },
749
+ [validateField]
750
+ );
646
751
  const polymorphicOnValueChange = useCallback(
647
752
  (...args) => {
648
753
  const value = args[args.length - 1];
@@ -665,22 +770,26 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
665
770
  },
666
771
  [validateField]
667
772
  );
668
- return {
669
- state,
670
- setState,
671
- touched,
672
- errors: errors2,
673
- on,
674
- helpers,
675
- onBlur,
676
- onValueChange: polymorphicOnValueChange,
677
- onSelectionChange: polymorphicOnSelectionChange,
678
- isDirty: touched.size > 0,
679
- hasInvalidValues: validateAll,
680
- resetForm: (preservedKeys) => {
681
- if (preservedKeys && preservedKeys.length > 0) {
773
+ const onFormSubmit = useCallback(
774
+ (fn) => (e) => {
775
+ e.preventDefault();
776
+ if (validateAll()) return;
777
+ fn(stateRef.current, e);
778
+ },
779
+ [validateAll]
780
+ );
781
+ const onFormSubmitPropRef = useRef(onFormSubmitProp);
782
+ onFormSubmitPropRef.current = onFormSubmitProp;
783
+ const resetOnSubmitRef = useRef(resetOnSubmit);
784
+ resetOnSubmitRef.current = resetOnSubmit;
785
+ const keepValuesPropRef = useRef(keepValuesProp);
786
+ keepValuesPropRef.current = keepValuesProp;
787
+ const handleReset = useCallback(
788
+ (options) => {
789
+ const { keepValues } = options || {};
790
+ if (keepValues && keepValues.length > 0) {
682
791
  const nextState = { ...initialState };
683
- preservedKeys.forEach((k) => {
792
+ keepValues.forEach((k) => {
684
793
  if (stateRef.current[k] !== void 0)
685
794
  nextState[k] = stateRef.current[k];
686
795
  });
@@ -688,25 +797,59 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
688
797
  } else {
689
798
  setState(initialState);
690
799
  }
691
- setTouched(/* @__PURE__ */ new Map());
692
- setErrors(/* @__PURE__ */ new Map());
800
+ setMetadata(/* @__PURE__ */ new Map());
693
801
  },
694
- resetTouched: (preservedKeys) => {
695
- if (preservedKeys && preservedKeys.length > 0) {
696
- setTouched((prev) => {
697
- const next = /* @__PURE__ */ new Map();
698
- for (const [k, v] of prev.entries()) {
699
- if (preservedKeys.some((pk) => k.startsWith(String(pk)))) {
700
- next.set(k, v);
701
- }
702
- }
703
- return next;
704
- });
705
- } else {
706
- setTouched(/* @__PURE__ */ new Map());
707
- }
708
- }
709
- };
802
+ [initialState]
803
+ );
804
+ const validateAllRef = useRef(validateAll);
805
+ validateAllRef.current = validateAll;
806
+ const ControlledForm = useMemo(() => {
807
+ return (props) => {
808
+ const { onSubmit, ...rest } = props;
809
+ const handleSubmit = (e) => {
810
+ e.preventDefault();
811
+ if (validateAllRef.current()) {
812
+ return;
813
+ }
814
+ onFormSubmitPropRef.current?.(stateRef.current, e);
815
+ if (resetOnSubmitRef.current) {
816
+ handleReset({ keepValues: keepValuesPropRef.current });
817
+ }
818
+ onSubmit?.(stateRef.current, e);
819
+ };
820
+ return /* @__PURE__ */ jsx(Form, { onSubmit: handleSubmit, ...rest });
821
+ };
822
+ }, []);
823
+ return useMemo(
824
+ () => ({
825
+ state,
826
+ setState,
827
+ metadata,
828
+ on,
829
+ helpers,
830
+ onFieldChange: polymorphicOnValueChange,
831
+ onFieldBlur: onBlur,
832
+ onSelectionChange: polymorphicOnSelectionChange,
833
+ isDirty: Array.from(metadata.values()).some((m) => m.isTouched),
834
+ onFormReset: handleReset,
835
+ onFormSubmit,
836
+ ControlledForm
837
+ }),
838
+ [
839
+ state,
840
+ setState,
841
+ metadata,
842
+ on,
843
+ helpers,
844
+ onBlur,
845
+ polymorphicOnValueChange,
846
+ polymorphicOnSelectionChange,
847
+ validateAll,
848
+ onFormSubmit,
849
+ ControlledForm,
850
+ initialState
851
+ ]
852
+ );
710
853
  }
711
854
  export {
712
855
  NextUIError,