@juantroconisf/lib 7.0.0 → 8.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.js CHANGED
@@ -35,7 +35,7 @@ var NextUIError = class {
35
35
  };
36
36
 
37
37
  // src/hooks/useForm.tsx
38
- var import_react = require("react");
38
+ var import_react2 = require("react");
39
39
 
40
40
  // src/utils/utils.ts
41
41
  function handleNestedChange({
@@ -45,7 +45,7 @@ function handleNestedChange({
45
45
  hasNestedValues = false
46
46
  }) {
47
47
  if (!hasNestedValues) return { ...state, [id]: value };
48
- const propertyDepth = String(id).split("."), newValues = state;
48
+ const propertyDepth = String(id).split("."), newValues = { ...state };
49
49
  let current = newValues;
50
50
  for (let i = 0; i < propertyDepth.length - 1; i++) {
51
51
  const key = propertyDepth[i];
@@ -81,141 +81,131 @@ function handleArrayItemChange({
81
81
  function getNestedValue(obj, path) {
82
82
  return path.split(".").reduce((acc, key) => acc?.[key], obj);
83
83
  }
84
- function removeCompositeKeysByPrefix(map2, prefix) {
85
- const result = new Map(map2);
86
- for (const key of map2.keys()) {
84
+ function removeCompositeKeysByPrefix(map, prefix) {
85
+ const result = new Map(map);
86
+ for (const key of map.keys()) {
87
87
  if (key.startsWith(prefix)) {
88
88
  result.delete(key);
89
89
  }
90
90
  }
91
91
  return result;
92
92
  }
93
- function setNestedValue(state, dotPath, value) {
94
- const keys = dotPath.split(".");
95
- const copy = { ...state };
96
- let current = copy;
97
- for (let i = 0; i < keys.length - 1; i++) {
98
- current[keys[i]] = { ...current[keys[i]] };
99
- current = current[keys[i]];
100
- }
101
- current[keys[keys.length - 1]] = value;
102
- return copy;
103
- }
104
- var regex = {
105
- 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,}))$/,
106
- password: /^(?!.*\s)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[~`!@#$%^&*()--+={}[\]|:;"'<>,.?/_₹]).{8,24}$/
107
- };
108
- var map = {
109
- string: (val) => Boolean(val),
110
- number: (val) => String(val) !== "",
111
- object: (val) => val !== null && Object.keys(val).length > 0
112
- };
113
- var requiredValidation = (value) => Array.isArray(value) ? value.length > 0 : map[typeof value](value);
114
- var errors = {
115
- required: {
116
- validate: (val, isRequired) => !isRequired || requiredValidation(val),
117
- msg: "REQUIRED"
118
- },
119
- min: {
120
- validate: (val, min) => val >= min,
121
- msg: "VALUE_LOW"
122
- },
123
- max: {
124
- validate: (val, max) => val <= max,
125
- msg: "VALUE_HIGH"
126
- },
127
- minLength: {
128
- validate: (val = "", min) => val.length >= min,
129
- msg: "TOO_SHORT"
130
- },
131
- maxLength: {
132
- validate: (val = "", max) => val.length <= max,
133
- msg: "TOO_LONG"
134
- },
135
- pattern: {
136
- validate: (val, pattern) => new RegExp(pattern).test(val),
137
- msg: "PATTERN_INVALID"
138
- },
139
- equal: {
140
- validate: (val, comparison) => val === comparison,
141
- msg: "NOT_EQUAL"
142
- },
143
- numberIsEqual: {
144
- validate: (val, comparison) => val === comparison,
145
- msg: "NOT_EQUAL"
146
- },
147
- email: {
148
- validate: (val) => new RegExp(regex.email).test(val),
149
- msg: "INVALID_EMAIL"
150
- },
151
- password: {
152
- validate: (val) => new RegExp(regex.password).test(val),
153
- msg: "INVALID_PASSWORD"
93
+
94
+ // src/hooks/useComponentLang.tsx
95
+ var import_yup = require("yup");
96
+ var import_react = require("react");
97
+
98
+ // src/assets/translations.ts
99
+ var translations = {
100
+ en: {
101
+ mixed: {
102
+ default: "Invalid value",
103
+ required: "This field is required",
104
+ oneOf: "Must be one of: ${values}",
105
+ notOneOf: "Cannot be any of: ${values}",
106
+ notType: "Incorrect data format",
107
+ defined: "Must be defined"
108
+ },
109
+ string: {
110
+ length: "Must be exactly ${length} characters",
111
+ min: "Must be at least ${min} characters",
112
+ max: "Must be at most ${max} characters",
113
+ matches: 'Must match: "${regex}"',
114
+ email: "Enter a valid email address",
115
+ url: "Enter a valid URL",
116
+ uuid: "Enter a valid UUID",
117
+ trim: "Remove leading/trailing spaces",
118
+ lowercase: "Must be in lowercase",
119
+ uppercase: "Must be in uppercase",
120
+ password: "Your password doesn't meet the security criteria."
121
+ },
122
+ number: {
123
+ min: "Value must be ${min} or greater",
124
+ max: "Value must be ${max} or less",
125
+ lessThan: "Must be less than ${less}",
126
+ moreThan: "Must be greater than ${more}",
127
+ positive: "Must be a positive number",
128
+ negative: "Must be a negative number",
129
+ integer: "Must be a whole number"
130
+ },
131
+ date: {
132
+ min: "Date must be after ${min}",
133
+ max: "Date must be before ${max}"
134
+ },
135
+ boolean: {
136
+ isValue: "Must be ${value}"
137
+ },
138
+ object: {
139
+ noUnknown: "Contains unknown properties"
140
+ },
141
+ array: {
142
+ min: "Must have at least ${min} items",
143
+ max: "Must have ${max} items or fewer",
144
+ length: "Must have exactly ${length} items"
145
+ }
154
146
  },
155
- custom: {
156
- validate: (_, bool) => bool,
157
- msg: "INVALID"
147
+ es: {
148
+ mixed: {
149
+ default: "Valor no v\xE1lido",
150
+ required: "Este campo es obligatorio",
151
+ oneOf: "Debe ser uno de: ${values}",
152
+ notOneOf: "No puede ser ninguno de: ${values}",
153
+ defined: "Debe estar definido",
154
+ notType: "Formato de dato incorrecto"
155
+ },
156
+ string: {
157
+ length: "Debe tener exactamente ${length} caracteres",
158
+ min: "Debe tener al menos ${min} caracteres",
159
+ max: "Debe tener como m\xE1ximo ${max} caracteres",
160
+ matches: 'Debe coincidir con: "${regex}"',
161
+ email: "Ingresa un correo electr\xF3nico v\xE1lido",
162
+ url: "Ingresa una URL v\xE1lida",
163
+ uuid: "Ingresa un UUID v\xE1lido",
164
+ trim: "No debe contener espacios al inicio o final",
165
+ lowercase: "Debe estar en min\xFAsculas",
166
+ uppercase: "Debe estar en may\xFAsculas",
167
+ password: "Tu contrase\xF1a no cumple con los requisitos de seguridad."
168
+ },
169
+ number: {
170
+ min: "Debe ser mayor o igual a ${min}",
171
+ max: "Debe ser menor o igual a ${max}",
172
+ lessThan: "Debe ser menor a ${less}",
173
+ moreThan: "Debe ser mayor a ${more}",
174
+ positive: "Debe ser un n\xFAmero positivo",
175
+ negative: "Debe ser un n\xFAmero negativo",
176
+ integer: "Debe ser un n\xFAmero entero"
177
+ },
178
+ date: {
179
+ min: "La fecha debe ser posterior a ${min}",
180
+ max: "La fecha debe ser anterior a ${max}"
181
+ },
182
+ boolean: {
183
+ isValue: "Debe ser ${value}"
184
+ },
185
+ object: {
186
+ noUnknown: "Contiene propiedades no permitidas"
187
+ },
188
+ array: {
189
+ min: "Debe tener al menos ${min} elementos",
190
+ max: "Debe tener como m\xE1ximo ${max} elementos",
191
+ length: "Debe tener ${length} elementos"
192
+ }
158
193
  }
159
194
  };
160
195
 
161
- // lang/en.json
162
- 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" };
163
-
164
- // lang/es.json
165
- 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" };
166
-
167
196
  // src/hooks/useComponentLang.tsx
168
197
  var cookieName = "LOCALE";
169
- var langMap = {
170
- en: en_default,
171
- es: es_default
172
- };
173
198
  var getClientCookie = () => {
174
199
  const value = "; " + document.cookie, decodedValue = decodeURIComponent(value), parts = decodedValue.split("; " + cookieName + "=");
175
200
  if (parts.length === 2) return parts.pop()?.split(";").shift();
176
201
  };
177
- var getServerCookie = () => {
178
- try {
179
- const { cookies } = require("next/headers");
180
- return cookies().get(cookieName)?.value;
181
- } catch {
182
- return "es";
183
- }
184
- };
185
202
  function useComponentLanguage() {
186
- const isServer = typeof window === "undefined", locale = (isServer ? getServerCookie() : getClientCookie()) || "en";
187
- return {
188
- locale,
189
- lang: langMap[locale]
190
- };
191
- }
192
-
193
- // src/hooks/useValidate.tsx
194
- var validProps = {
195
- isInvalid: false,
196
- errorMessage: ""
197
- };
198
- function useValidate() {
199
- const { lang } = useComponentLanguage();
200
- const performValidations = (value, validationTypes, errorMessages) => {
201
- if (!validationTypes) return validProps;
202
- const items = Object.entries(validationTypes), requiredExist = validationTypes?.required !== void 0, isRequired = requiredExist ? validationTypes.required : false;
203
- if (value === "" && !isRequired) return validProps;
204
- let errorFound = validProps;
205
- for (const [key, opts] of items) {
206
- if (opts === null) continue;
207
- const { validate, msg } = errors[key], isInvalid = !validate(value, opts);
208
- if (isInvalid) {
209
- errorFound = {
210
- isInvalid,
211
- errorMessage: errorMessages?.[key] || lang[msg]
212
- };
213
- break;
214
- }
203
+ (0, import_react.useEffect)(() => {
204
+ const locale = getClientCookie() || "en";
205
+ if (translations[locale]) {
206
+ (0, import_yup.setLocale)(translations[locale]);
215
207
  }
216
- return errorFound;
217
- };
218
- return { performValidations };
208
+ }, []);
219
209
  }
220
210
 
221
211
  // src/hooks/useForm.utils.ts
@@ -313,19 +303,36 @@ function resolveFieldData(args, state, getIndex, getNestedValue2) {
313
303
  }
314
304
 
315
305
  // src/hooks/useForm.tsx
316
- function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
317
- const [state, setState] = (0, import_react.useState)(initialState);
318
- const [touched, setTouched] = (0, import_react.useState)(/* @__PURE__ */ new Map());
319
- const [errors2, setErrors] = (0, import_react.useState)(/* @__PURE__ */ new Map());
320
- const { performValidations } = useValidate();
321
- const stateRef = (0, import_react.useRef)(state);
322
- const touchedRef = (0, import_react.useRef)(touched);
323
- const errorsRef = (0, import_react.useRef)(errors2);
306
+ var import_yup2 = require("yup");
307
+ var DEFAULT_OPTIONS = {};
308
+ function useForm(schema, { arrayIdentifiers } = DEFAULT_OPTIONS) {
309
+ const { initialState, validationSchema } = (0, import_react2.useMemo)(() => {
310
+ const state2 = {};
311
+ const extractedRules = {};
312
+ Object.entries(schema).forEach(([key, value]) => {
313
+ if ((0, import_yup2.isSchema)(value)) {
314
+ try {
315
+ state2[key] = value.getDefault();
316
+ } catch {
317
+ state2[key] = void 0;
318
+ }
319
+ extractedRules[key] = value;
320
+ } else {
321
+ state2[key] = value;
322
+ }
323
+ });
324
+ return {
325
+ initialState: state2,
326
+ validationSchema: (0, import_yup2.object)().shape(extractedRules)
327
+ };
328
+ }, [schema]);
329
+ const [state, setState] = (0, import_react2.useState)(initialState), [metadata, setMetadata] = (0, import_react2.useState)(/* @__PURE__ */ new Map());
330
+ useComponentLanguage();
331
+ const stateRef = (0, import_react2.useRef)(state), metadataRef = (0, import_react2.useRef)(metadata);
324
332
  stateRef.current = state;
325
- touchedRef.current = touched;
326
- errorsRef.current = errors2;
327
- const indexMap = (0, import_react.useMemo)(() => {
328
- const map2 = /* @__PURE__ */ new Map();
333
+ metadataRef.current = metadata;
334
+ const indexMap = (0, import_react2.useMemo)(() => {
335
+ const map = /* @__PURE__ */ new Map();
329
336
  const traverse = (current, path) => {
330
337
  if (!current || typeof current !== "object") return;
331
338
  if (Array.isArray(current)) {
@@ -341,7 +348,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
341
348
  traverse(item, `${path}.${index}`);
342
349
  }
343
350
  });
344
- map2.set(path, itemMap);
351
+ map.set(path, itemMap);
345
352
  } else {
346
353
  Object.keys(current).forEach((key) => {
347
354
  const nextPath = path ? `${path}.${key}` : key;
@@ -350,106 +357,140 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
350
357
  }
351
358
  };
352
359
  traverse(state, "");
353
- return map2;
360
+ return map;
354
361
  }, [state, arrayIdentifiers]);
355
- const indexMapRef = (0, import_react.useRef)(indexMap);
362
+ const indexMapRef = (0, import_react2.useRef)(indexMap);
356
363
  indexMapRef.current = indexMap;
357
- const getIndex = (0, import_react.useCallback)((arrayKey, itemId) => {
364
+ const getIndex = (0, import_react2.useCallback)((arrayKey, itemId) => {
358
365
  return indexMapRef.current.get(arrayKey)?.get(itemId);
359
366
  }, []);
360
- const getRule = (0, import_react.useCallback)(
361
- (path) => {
362
- if (rules?.[path]) return rules[path];
363
- const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
364
- return rules?.[genericPath];
365
- },
366
- [rules]
367
- );
368
- const getMessage = (0, import_react.useCallback)(
369
- (path) => {
370
- if (messages?.[path]) return messages[path];
367
+ const ruleCache = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
368
+ (0, import_react2.useMemo)(() => {
369
+ ruleCache.current.clear();
370
+ }, [validationSchema]);
371
+ const getRule = (0, import_react2.useCallback)((path, schema2) => {
372
+ if (ruleCache.current.has(path)) {
373
+ return ruleCache.current.get(path);
374
+ }
375
+ let rule;
376
+ try {
377
+ rule = (0, import_yup2.reach)(schema2, path);
378
+ } catch {
371
379
  const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
372
- return messages?.[genericPath];
380
+ try {
381
+ rule = (0, import_yup2.reach)(schema2, genericPath);
382
+ } catch {
383
+ rule = void 0;
384
+ }
385
+ }
386
+ ruleCache.current.set(path, rule);
387
+ return rule;
388
+ }, []);
389
+ const runValidation = (0, import_react2.useCallback)(
390
+ (ruleDef, value, compositeKey) => {
391
+ if ((0, import_yup2.isSchema)(ruleDef)) {
392
+ try {
393
+ ruleDef.validateSync(value);
394
+ return false;
395
+ } catch (err) {
396
+ const error = {
397
+ isInvalid: true,
398
+ errorMessage: err.message || "Invalid"
399
+ };
400
+ setMetadata((prev) => {
401
+ const newMap = new Map(prev);
402
+ const currentMeta = newMap.get(compositeKey) || {
403
+ isTouched: false,
404
+ isInvalid: false,
405
+ errorMessage: ""
406
+ };
407
+ newMap.set(compositeKey, { ...currentMeta, ...error });
408
+ return newMap;
409
+ });
410
+ return true;
411
+ }
412
+ }
413
+ return false;
373
414
  },
374
- [messages]
415
+ []
375
416
  );
376
- const validateField = (0, import_react.useCallback)(
377
- (compositeKey, fieldPath, value, extraContext) => {
378
- let ruleDef = getRule(fieldPath);
379
- if (!ruleDef) {
380
- const stripped = fieldPath.replace(/\.@\d+/g, "").replace(/\.@\d+$/, "");
381
- if (stripped !== fieldPath) ruleDef = getRule(stripped);
417
+ const validateField = (0, import_react2.useCallback)(
418
+ (compositeKey, fieldPath, value) => {
419
+ let schemaRule = getRule(fieldPath, validationSchema);
420
+ if (schemaRule) {
421
+ if (runValidation(schemaRule, value, compositeKey)) return true;
382
422
  }
383
- const rule = typeof ruleDef === "function" ? ruleDef(
384
- value,
385
- stateRef.current,
386
- extraContext?.item,
387
- extraContext?.index
388
- ) : ruleDef;
389
- let message = getMessage(fieldPath);
390
- if (!message && fieldPath !== fieldPath.replace(/\.@\d+/, "")) {
391
- message = getMessage(fieldPath.replace(/\.@\d+/, ""));
392
- }
393
- const error = performValidations(value, rule, message);
394
- setErrors((prev) => {
423
+ setMetadata((prev) => {
395
424
  const newMap = new Map(prev);
396
- newMap.set(compositeKey, error);
425
+ const currentMeta = newMap.get(compositeKey) || {
426
+ isTouched: false,
427
+ isInvalid: false,
428
+ errorMessage: ""
429
+ };
430
+ newMap.set(compositeKey, {
431
+ ...currentMeta,
432
+ isInvalid: false,
433
+ errorMessage: ""
434
+ });
397
435
  return newMap;
398
436
  });
399
- return error.isInvalid;
437
+ return false;
400
438
  },
401
- [getRule, getMessage, performValidations]
439
+ [getRule, runValidation, validationSchema]
402
440
  );
403
- const validateAll = (0, import_react.useCallback)(() => {
404
- if (!rules) return false;
405
- const nextErrors = /* @__PURE__ */ new Map();
406
- let hasInvalid = false;
407
- const processRule = (ruleKey, ruleVal) => {
408
- const isGeneric = !ruleKey.match(/\.\d+\./) && !ruleKey.match(/\.@\d+/);
409
- const parts = ruleKey.split(".");
410
- let arrayKey = "";
411
- let arrayIndexInPath = -1;
412
- for (let i = 0; i < parts.length; i++) {
413
- if (indexMapRef.current.has(parts[i])) {
414
- arrayKey = parts[i];
415
- arrayIndexInPath = i;
416
- break;
417
- }
418
- }
419
- if (arrayKey && arrayIndexInPath !== -1) {
420
- const itemMap = indexMapRef.current.get(arrayKey);
421
- if (itemMap) {
422
- itemMap.forEach((idx, itemId) => {
423
- const suffix = parts.slice(arrayIndexInPath + 1).join(".");
424
- const compositeKey = `${arrayKey}.${itemId}` + (suffix ? `.${suffix}` : "");
425
- const item = stateRef.current[arrayKey][idx];
426
- const val = getNestedValue(item, suffix);
427
- const rule = typeof ruleVal === "function" ? ruleVal(val, stateRef.current, item, idx) : ruleVal;
428
- const msg = getMessage(ruleKey);
429
- const err = performValidations(val, rule, msg);
430
- nextErrors.set(compositeKey, err);
431
- if (err.isInvalid) hasInvalid = true;
441
+ const validateAll = (0, import_react2.useCallback)(() => {
442
+ if (!validationSchema) return false;
443
+ let hasError = false;
444
+ const newMetadata = new Map(metadataRef.current);
445
+ try {
446
+ validationSchema.validateSync(state, { abortEarly: false });
447
+ } catch (err) {
448
+ hasError = true;
449
+ if (err.inner) {
450
+ err.inner.forEach((validationError) => {
451
+ const yupPath = validationError.path;
452
+ const dotPath = yupPath.replace(/\[(\d+)\]/g, ".$1");
453
+ const parts = dotPath.split(".");
454
+ let current = state;
455
+ const compositeParts = [];
456
+ for (let i = 0; i < parts.length; i++) {
457
+ const part = parts[i];
458
+ if (Array.isArray(current)) {
459
+ const index = parseInt(part, 10);
460
+ const item = current[index];
461
+ if (item && typeof item === "object") {
462
+ const genericPath = compositeParts.join(".").replace(/\.\d+/g, "");
463
+ const idKey = arrayIdentifiers?.[genericPath] || "id";
464
+ const id = item[idKey];
465
+ compositeParts.push(String(id !== void 0 ? id : index));
466
+ } else {
467
+ compositeParts.push(part);
468
+ }
469
+ current = item;
470
+ } else {
471
+ compositeParts.push(part);
472
+ current = current?.[part];
473
+ }
474
+ }
475
+ const compositeKey = compositeParts.join(".");
476
+ const currentMeta = newMetadata.get(compositeKey) || {
477
+ isTouched: false,
478
+ isInvalid: false,
479
+ errorMessage: ""
480
+ };
481
+ newMetadata.set(compositeKey, {
482
+ ...currentMeta,
483
+ isTouched: true,
484
+ isInvalid: true,
485
+ errorMessage: validationError.message
432
486
  });
433
- }
434
- } else {
435
- const val = getNestedValue(stateRef.current, ruleKey);
436
- const rule = typeof ruleVal === "function" ? ruleVal(val, stateRef.current) : ruleVal;
437
- const msg = getMessage(ruleKey);
438
- const err = performValidations(val, rule, msg);
439
- nextErrors.set(ruleKey, err);
440
- if (err.isInvalid) hasInvalid = true;
487
+ });
441
488
  }
442
- };
443
- Object.entries(rules).forEach(([k, v]) => processRule(k, v));
444
- setErrors(nextErrors);
445
- setTouched((prev) => {
446
- const next = new Map(prev);
447
- nextErrors.forEach((_, k) => next.set(k, true));
448
- return next;
449
- });
450
- return hasInvalid;
451
- }, [rules, getMessage, performValidations]);
452
- const handleFieldChange = (0, import_react.useCallback)(
489
+ }
490
+ setMetadata(newMetadata);
491
+ return hasError;
492
+ }, [validationSchema, state, arrayIdentifiers]);
493
+ const handleFieldChange = (0, import_react2.useCallback)(
453
494
  (resolution, newValue) => {
454
495
  if (!resolution) return;
455
496
  const {
@@ -462,17 +503,29 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
462
503
  parentId,
463
504
  nestedField
464
505
  } = resolution;
506
+ let finalValue = newValue;
507
+ let rule = getRule(fieldPath, validationSchema);
508
+ if (rule && rule.type === "array" && type === "primitiveArray" /* PrimitiveArray */ && rule.innerType) {
509
+ rule = rule.innerType;
510
+ }
511
+ if (rule && rule.type === "string") {
512
+ try {
513
+ finalValue = rule.cast(newValue);
514
+ } catch {
515
+ }
516
+ }
465
517
  setState((prev) => {
466
518
  if (type === "scalar" /* Scalar */) {
467
519
  return handleNestedChange({
468
520
  state: prev,
469
521
  id: compositeKey,
470
- value: newValue
522
+ value: finalValue,
523
+ hasNestedValues: compositeKey.includes(".")
471
524
  });
472
525
  }
473
526
  if (type === "primitiveArray" /* PrimitiveArray */) {
474
527
  const arr = [...prev[arrayKey]];
475
- arr[index] = newValue;
528
+ arr[index] = finalValue;
476
529
  return { ...prev, [arrayKey]: arr };
477
530
  }
478
531
  if (type === "objectArray" /* ObjectArray */) {
@@ -481,7 +534,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
481
534
  arrayKey,
482
535
  index,
483
536
  field: resolution.field,
484
- value: newValue
537
+ value: finalValue
485
538
  });
486
539
  }
487
540
  if (type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
@@ -490,47 +543,46 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
490
543
  const parentArr = [...prev[parentKey]];
491
544
  const pItem = { ...parentArr[pIndex] };
492
545
  const nestedArr = [...getNestedValue(pItem, nestedField) || []];
493
- nestedArr[index] = newValue;
546
+ nestedArr[index] = finalValue;
494
547
  pItem[nestedField] = nestedArr;
495
- const updatedItem = setNestedValue(pItem, nestedField, nestedArr);
496
- parentArr[pIndex] = updatedItem;
548
+ parentArr[pIndex] = pItem;
497
549
  return { ...prev, [parentKey]: parentArr };
498
550
  }
499
551
  return prev;
500
552
  });
501
- let extraContext = {};
502
- if (type === "objectArray" /* ObjectArray */ || type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
503
- const idx = index;
504
- const arrKey = arrayKey || parentKey;
505
- extraContext = {
506
- index: idx,
507
- item: stateRef.current[arrKey]?.[idx]
508
- };
509
- }
510
- validateField(compositeKey, fieldPath, newValue, extraContext);
553
+ validateField(compositeKey, fieldPath, finalValue);
511
554
  },
512
- [getIndex, validateField]
555
+ [getIndex, validateField, getRule, validationSchema]
513
556
  );
514
- const createHandlers = (0, import_react.useCallback)(
557
+ const createHandlers = (0, import_react2.useCallback)(
515
558
  (resolution) => {
516
559
  if (!resolution) return {};
517
560
  const { compositeKey, fieldPath, value } = resolution;
518
- const err = errorsRef.current.get(compositeKey);
519
- const isTouched = touchedRef.current.get(compositeKey);
561
+ const meta = metadataRef.current.get(compositeKey);
562
+ const isTouched = meta?.isTouched;
520
563
  return {
521
564
  id: compositeKey,
522
- isInvalid: Boolean(isTouched && err?.isInvalid),
523
- errorMessage: isTouched ? err?.errorMessage || "" : "",
565
+ isInvalid: Boolean(isTouched && meta?.isInvalid),
566
+ errorMessage: isTouched ? meta?.errorMessage || "" : "",
524
567
  onBlur: () => {
525
- if (touchedRef.current.get(compositeKey)) return;
568
+ if (metadataRef.current.get(compositeKey)?.isTouched) return;
526
569
  validateField(compositeKey, fieldPath, value);
527
- setTouched((prev) => new Map(prev).set(compositeKey, true));
570
+ setMetadata((prev) => {
571
+ const newMap = new Map(prev);
572
+ const current = newMap.get(compositeKey) || {
573
+ isTouched: false,
574
+ isInvalid: false,
575
+ errorMessage: ""
576
+ };
577
+ newMap.set(compositeKey, { ...current, isTouched: true });
578
+ return newMap;
579
+ });
528
580
  }
529
581
  };
530
582
  },
531
583
  [validateField]
532
584
  );
533
- const on = (0, import_react.useMemo)(
585
+ const on = (0, import_react2.useMemo)(
534
586
  () => ({
535
587
  input: (...args) => {
536
588
  const data = resolveFieldData(
@@ -584,7 +636,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
584
636
  }),
585
637
  [createHandlers, getIndex, handleFieldChange]
586
638
  );
587
- const helpers = (0, import_react.useMemo)(
639
+ const helpers = (0, import_react2.useMemo)(
588
640
  () => ({
589
641
  addItem: (arrayKey, item, index) => {
590
642
  setState((prev) => {
@@ -606,8 +658,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
606
658
  });
607
659
  if (itemId !== void 0) {
608
660
  const prefix = `${String(arrayKey)}.${itemId}.`;
609
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
610
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
661
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
611
662
  }
612
663
  },
613
664
  removeById: (arrayKey, itemId) => {
@@ -619,8 +670,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
619
670
  return { ...prev, [arrayKey]: arr };
620
671
  });
621
672
  const prefix = `${String(arrayKey)}.${itemId}.`;
622
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
623
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
673
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
624
674
  }
625
675
  },
626
676
  updateItem: (arrayKey, index, value) => {
@@ -658,11 +708,23 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
658
708
  }),
659
709
  [getIndex, arrayIdentifiers]
660
710
  );
661
- const onBlur = (id) => {
662
- validateField(String(id), String(id), stateRef.current[id]);
663
- setTouched((prev) => new Map(prev).set(String(id), true));
664
- };
665
- const polymorphicOnValueChange = (0, import_react.useCallback)(
711
+ const onBlur = (0, import_react2.useCallback)(
712
+ (id) => {
713
+ validateField(String(id), String(id), stateRef.current[id]);
714
+ setMetadata((prev) => {
715
+ const newMap = new Map(prev);
716
+ const current = newMap.get(String(id)) || {
717
+ isTouched: false,
718
+ isInvalid: false,
719
+ errorMessage: ""
720
+ };
721
+ newMap.set(String(id), { ...current, isTouched: true });
722
+ return newMap;
723
+ });
724
+ },
725
+ [validateField]
726
+ );
727
+ const polymorphicOnValueChange = (0, import_react2.useCallback)(
666
728
  (...args) => {
667
729
  const value = args[args.length - 1];
668
730
  const idArgs = args.slice(0, args.length - 1);
@@ -676,7 +738,7 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
676
738
  },
677
739
  [getIndex, handleFieldChange]
678
740
  );
679
- const polymorphicOnSelectionChange = (0, import_react.useCallback)(
741
+ const polymorphicOnSelectionChange = (0, import_react2.useCallback)(
680
742
  (id, val) => {
681
743
  const fixed = typeof val === "string" || val === null ? val : Array.from(val);
682
744
  setState((prev) => handleNestedChange({ state: prev, id, value: fixed }));
@@ -684,48 +746,71 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
684
746
  },
685
747
  [validateField]
686
748
  );
687
- return {
688
- state,
689
- setState,
690
- touched,
691
- errors: errors2,
692
- on,
693
- helpers,
694
- onBlur,
695
- onValueChange: polymorphicOnValueChange,
696
- onSelectionChange: polymorphicOnSelectionChange,
697
- isDirty: touched.size > 0,
698
- hasInvalidValues: validateAll,
699
- resetForm: (preservedKeys) => {
700
- if (preservedKeys && preservedKeys.length > 0) {
701
- const nextState = { ...initialState };
702
- preservedKeys.forEach((k) => {
703
- if (stateRef.current[k] !== void 0)
704
- nextState[k] = stateRef.current[k];
705
- });
706
- setState(nextState);
707
- } else {
708
- setState(initialState);
709
- }
710
- setTouched(/* @__PURE__ */ new Map());
711
- setErrors(/* @__PURE__ */ new Map());
749
+ const onSubmit = (0, import_react2.useCallback)(
750
+ (fn) => (e) => {
751
+ e.preventDefault();
752
+ if (validateAll()) return;
753
+ fn(stateRef.current, e);
712
754
  },
713
- resetTouched: (preservedKeys) => {
714
- if (preservedKeys && preservedKeys.length > 0) {
715
- setTouched((prev) => {
716
- const next = /* @__PURE__ */ new Map();
717
- for (const [k, v] of prev.entries()) {
718
- if (preservedKeys.some((pk) => k.startsWith(String(pk)))) {
719
- next.set(k, v);
720
- }
721
- }
722
- return next;
723
- });
724
- } else {
725
- setTouched(/* @__PURE__ */ new Map());
726
- }
727
- }
728
- };
755
+ [validateAll]
756
+ );
757
+ return (0, import_react2.useMemo)(
758
+ () => ({
759
+ state,
760
+ setState,
761
+ metadata,
762
+ on,
763
+ helpers,
764
+ onFieldChange: polymorphicOnValueChange,
765
+ onFieldBlur: onBlur,
766
+ onSelectionChange: polymorphicOnSelectionChange,
767
+ isDirty: Array.from(metadata.values()).some((m) => m.isTouched),
768
+ reset: (options) => {
769
+ const { preservedStateKeys, preserveTouched } = options || {};
770
+ if (preservedStateKeys && preservedStateKeys.length > 0) {
771
+ const nextState = { ...initialState };
772
+ preservedStateKeys.forEach((k) => {
773
+ if (stateRef.current[k] !== void 0)
774
+ nextState[k] = stateRef.current[k];
775
+ });
776
+ setState(nextState);
777
+ } else {
778
+ setState(initialState);
779
+ }
780
+ if (preserveTouched) {
781
+ setMetadata((prev) => {
782
+ const next = /* @__PURE__ */ new Map();
783
+ prev.forEach((v, k) => {
784
+ if (v.isTouched) {
785
+ next.set(k, {
786
+ isTouched: true,
787
+ isInvalid: false,
788
+ errorMessage: ""
789
+ });
790
+ }
791
+ });
792
+ return next;
793
+ });
794
+ } else {
795
+ setMetadata(/* @__PURE__ */ new Map());
796
+ }
797
+ },
798
+ onSubmit
799
+ }),
800
+ [
801
+ state,
802
+ setState,
803
+ metadata,
804
+ on,
805
+ helpers,
806
+ onBlur,
807
+ polymorphicOnValueChange,
808
+ polymorphicOnSelectionChange,
809
+ validateAll,
810
+ onSubmit,
811
+ initialState
812
+ ]
813
+ );
729
814
  }
730
815
  // Annotate the CommonJS export names for ESM import in node:
731
816
  0 && (module.exports = {