@juantroconisf/lib 6.1.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,667 +81,576 @@ 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
- };
203
+ (0, import_react.useEffect)(() => {
204
+ const locale = getClientCookie() || "en";
205
+ if (translations[locale]) {
206
+ (0, import_yup.setLocale)(translations[locale]);
207
+ }
208
+ }, []);
191
209
  }
192
210
 
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]
211
+ // src/hooks/useForm.utils.ts
212
+ function resolveFieldData(args, state, getIndex, getNestedValue2) {
213
+ const argCount = args.length;
214
+ if (argCount === 1) {
215
+ const id = args[0];
216
+ return {
217
+ type: "scalar" /* Scalar */,
218
+ compositeKey: id,
219
+ fieldPath: id,
220
+ value: getNestedValue2(state, id),
221
+ id
222
+ };
223
+ }
224
+ if (argCount === 2) {
225
+ const [arg0, arg1] = args;
226
+ if (typeof arg0 === "string" && arg0.includes(".")) {
227
+ const parts = arg0.split(".");
228
+ const arrayKey2 = parts[0];
229
+ if (Array.isArray(state[arrayKey2])) {
230
+ const field = parts.slice(1).join(".");
231
+ const itemId = arg1;
232
+ const index2 = getIndex(arrayKey2, itemId);
233
+ if (index2 === void 0) return null;
234
+ const arr2 = state[arrayKey2];
235
+ const item = arr2[index2];
236
+ const value = getNestedValue2(item, field);
237
+ return {
238
+ type: "objectArray" /* ObjectArray */,
239
+ compositeKey: `${arrayKey2}.${itemId}.${field}`,
240
+ fieldPath: arg0,
241
+ // "array.field"
242
+ value,
243
+ arrayKey: arrayKey2,
244
+ itemId,
245
+ field,
246
+ index: index2
212
247
  };
213
- break;
214
248
  }
215
249
  }
216
- return errorFound;
217
- };
218
- return { performValidations };
250
+ const arrayKey = arg0;
251
+ const index = arg1;
252
+ const arr = state[arrayKey];
253
+ return {
254
+ type: "primitiveArray" /* PrimitiveArray */,
255
+ compositeKey: `${arrayKey}.@${index}`,
256
+ fieldPath: `${arrayKey}`,
257
+ value: arr?.[index],
258
+ arrayKey,
259
+ index
260
+ };
261
+ }
262
+ if (argCount === 3) {
263
+ const [arrayKey, itemId, field] = args;
264
+ const index = getIndex(arrayKey, itemId);
265
+ if (index === void 0) return null;
266
+ const arr = state[arrayKey];
267
+ const item = arr[index];
268
+ const value = getNestedValue2(item, field);
269
+ return {
270
+ type: "objectArray" /* ObjectArray */,
271
+ compositeKey: `${arrayKey}.${itemId}.${field}`,
272
+ fieldPath: `${arrayKey}.${field}`,
273
+ // Normalized path for rules
274
+ value,
275
+ arrayKey,
276
+ itemId,
277
+ field,
278
+ index
279
+ };
280
+ }
281
+ if (argCount === 4) {
282
+ const [parentKey, parentId, field, index] = args;
283
+ const parentIndex = getIndex(parentKey, parentId);
284
+ if (parentIndex === void 0) return null;
285
+ const arr = state[parentKey];
286
+ const item = arr[parentIndex];
287
+ const nestedArr = getNestedValue2(item, field);
288
+ const value = Array.isArray(nestedArr) ? nestedArr[index] : void 0;
289
+ return {
290
+ type: "nestedPrimitiveArray" /* NestedPrimitiveArray */,
291
+ compositeKey: `${parentKey}.${parentId}.${field}.@${index}`,
292
+ fieldPath: `${parentKey}.${field}`,
293
+ // Roughly?
294
+ value,
295
+ parentKey,
296
+ parentId,
297
+ field,
298
+ index,
299
+ nestedField: field
300
+ };
301
+ }
302
+ return null;
219
303
  }
220
304
 
221
305
  // src/hooks/useForm.tsx
222
- function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
223
- const [state, setState] = (0, import_react.useState)(initialState), [touched, setTouched] = (0, import_react.useState)(/* @__PURE__ */ new Map()), [errors2, setErrors] = (0, import_react.useState)(/* @__PURE__ */ new Map()), { performValidations } = useValidate();
224
- const indexMap = (0, import_react.useMemo)(() => {
225
- const map2 = /* @__PURE__ */ new Map();
226
- for (const key in state) {
227
- if (Array.isArray(state[key])) {
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);
332
+ stateRef.current = state;
333
+ metadataRef.current = metadata;
334
+ const indexMap = (0, import_react2.useMemo)(() => {
335
+ const map = /* @__PURE__ */ new Map();
336
+ const traverse = (current, path) => {
337
+ if (!current || typeof current !== "object") return;
338
+ if (Array.isArray(current)) {
228
339
  const itemMap = /* @__PURE__ */ new Map();
229
- const idKey = arrayIdentifiers?.[key] || "id";
230
- state[key].forEach((item, index) => {
340
+ const genericPath = path.replace(/\.\d+/g, "");
341
+ const idKey = arrayIdentifiers?.[genericPath] || "id";
342
+ current.forEach((item, index) => {
231
343
  if (item && typeof item === "object") {
232
344
  const idValue = item[idKey];
233
345
  if (idValue !== void 0) {
234
346
  itemMap.set(idValue, index);
235
347
  }
348
+ traverse(item, `${path}.${index}`);
236
349
  }
237
350
  });
238
- map2.set(key, itemMap);
351
+ map.set(path, itemMap);
352
+ } else {
353
+ Object.keys(current).forEach((key) => {
354
+ const nextPath = path ? `${path}.${key}` : key;
355
+ traverse(current[key], nextPath);
356
+ });
239
357
  }
240
- }
241
- return map2;
358
+ };
359
+ traverse(state, "");
360
+ return map;
242
361
  }, [state, arrayIdentifiers]);
243
- const getIndex = (0, import_react.useCallback)(
244
- (arrayKey, itemId) => {
245
- return indexMap.get(arrayKey)?.get(itemId);
246
- },
247
- [indexMap]
248
- );
249
- const getRule = (path) => {
250
- if (rules?.[path]) return rules[path];
251
- const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
252
- return rules?.[genericPath];
253
- };
254
- const getMessage = (path) => {
255
- if (messages?.[path]) return messages[path];
256
- const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
257
- return messages?.[genericPath];
258
- };
259
- const validateInput = (compositeKey, value, ruleKey) => {
260
- const ruleDef = getRule(ruleKey);
261
- const rule = typeof ruleDef === "function" ? ruleDef(value, state) : ruleDef;
262
- const message = getMessage(ruleKey);
263
- const error = performValidations(value, rule, message);
264
- setErrors((prev) => new Map(prev).set(compositeKey, error));
265
- };
266
- const getUXProps = (0, import_react.useCallback)(
267
- (compositeKey) => {
268
- const inputError = errors2.get(compositeKey);
269
- const isTouched = touched.get(compositeKey);
270
- return {
271
- isInvalid: Boolean(isTouched && inputError?.isInvalid),
272
- errorMessage: isTouched ? inputError?.errorMessage || "" : ""
273
- };
274
- },
275
- [errors2, touched]
276
- );
277
- const onBlur = (id) => {
278
- validateInput(String(id), state[id], String(id));
279
- if (touched.get(String(id))) return;
280
- setTouched((prev) => new Map(prev).set(String(id), true));
281
- }, onValueChange = ((...args) => {
282
- if (args.length === 2) {
283
- const [id, value] = args;
284
- setState((prev) => handleNestedChange({ state: prev, id, value }));
285
- validateInput(String(id), value, String(id));
286
- return;
287
- }
288
- if (args.length === 3) {
289
- const [arrayKey, index, value] = args;
290
- setState((prev) => {
291
- const arr = [...prev[arrayKey]];
292
- arr[index] = value;
293
- return { ...prev, [arrayKey]: arr };
294
- });
295
- return;
296
- }
297
- if (args.length === 4) {
298
- const [arrayKey, itemId, field, value] = args;
299
- const index = getIndex(String(arrayKey), itemId);
300
- if (index === void 0) return;
301
- setState(
302
- (prev) => handleArrayItemChange({ state: prev, arrayKey, index, field, value })
303
- );
304
- validateItemInput(arrayKey, itemId, field, value);
305
- return;
362
+ const indexMapRef = (0, import_react2.useRef)(indexMap);
363
+ indexMapRef.current = indexMap;
364
+ const getIndex = (0, import_react2.useCallback)((arrayKey, itemId) => {
365
+ return indexMapRef.current.get(arrayKey)?.get(itemId);
366
+ }, []);
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);
306
374
  }
307
- if (args.length === 5) {
308
- const [parentKey, parentId, field, index, value] = args;
309
- const parentIndex = getIndex(String(parentKey), parentId);
310
- if (parentIndex === void 0) return;
311
- setState((prev) => {
312
- const parentArr = [...prev[parentKey]];
313
- const item = { ...parentArr[parentIndex] };
314
- const nestedArr = [...getNestedValue(item, field) || []];
315
- nestedArr[index] = value;
316
- const updatedItem = setNestedValue(item, field, nestedArr);
317
- parentArr[parentIndex] = updatedItem;
318
- return { ...prev, [parentKey]: parentArr };
319
- });
320
- return;
375
+ let rule;
376
+ try {
377
+ rule = (0, import_yup2.reach)(schema2, path);
378
+ } catch {
379
+ const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
380
+ try {
381
+ rule = (0, import_yup2.reach)(schema2, genericPath);
382
+ } catch {
383
+ rule = void 0;
384
+ }
321
385
  }
322
- }), onSelectionChange = (id, value) => {
323
- const fixedValue = typeof value === "string" || value === null ? value : Array.from(value);
324
- setState(
325
- (prev) => handleNestedChange({
326
- state: prev,
327
- id,
328
- value: fixedValue
329
- })
330
- );
331
- validateInput(String(id), fixedValue, String(id));
332
- };
333
- const getItemCompositeKey = (arrayKey, itemId, field) => `${arrayKey}.${itemId}.${field}`;
334
- const getPrimitiveCompositeKey = (arrayKey, index) => `${arrayKey}.@${index}`;
335
- const getNestedPrimitiveCompositeKey = (parentKey, parentId, field, index) => `${parentKey}.${parentId}.${field}.@${index}`;
336
- const validateItemInput = (arrayKey, itemId, field, value) => {
337
- const index = getIndex(String(arrayKey), itemId);
338
- if (index === void 0) return;
339
- const item = state[arrayKey][index];
340
- const compositeKey = getItemCompositeKey(String(arrayKey), itemId, field);
341
- let genericField = field.replace(/\.@\d+/, "");
342
- if (genericField === "")
343
- genericField = String(arrayKey);
344
- else genericField = `${String(arrayKey)}.${genericField}`;
345
- let effectivePath = `${String(arrayKey)}.${field}`;
346
- if (field === "") effectivePath = String(arrayKey);
347
- effectivePath = effectivePath.replace(/\.@\d+/g, "").replace(/\.@\d+$/, "");
348
- const ruleDef = getRule(effectivePath);
349
- const rule = typeof ruleDef === "function" ? ruleDef(value, state, item, index) : ruleDef;
350
- const message = getMessage(effectivePath);
351
- setErrors(
352
- (prev) => new Map(prev).set(compositeKey, performValidations(value, rule, message))
353
- );
354
- };
355
- const getItemUXProps = (0, import_react.useCallback)(
356
- (arrayKey, itemId, field) => {
357
- const compositeKey = getItemCompositeKey(arrayKey, itemId, field);
358
- const inputError = errors2.get(compositeKey);
359
- const isTouched = touched.get(compositeKey);
360
- return {
361
- isInvalid: Boolean(isTouched && inputError?.isInvalid),
362
- errorMessage: isTouched ? inputError?.errorMessage || "" : ""
363
- };
364
- },
365
- [errors2, touched]
366
- );
367
- const onItemBlur = (arrayKey, itemId, field) => {
368
- const index = getIndex(String(arrayKey), itemId);
369
- if (index === void 0) return;
370
- const arr = state[arrayKey];
371
- const value = getNestedValue(arr[index], field);
372
- validateItemInput(arrayKey, itemId, field, value);
373
- const compositeKey = getItemCompositeKey(String(arrayKey), itemId, field);
374
- if (touched.get(compositeKey)) return;
375
- setTouched((prev) => new Map(prev).set(compositeKey, true));
376
- };
377
- const onItemValueChange = (arrayKey, itemId, field, value) => {
378
- const index = getIndex(String(arrayKey), itemId);
379
- if (index === void 0) return;
380
- setState(
381
- (prev) => handleArrayItemChange({ state: prev, arrayKey, index, field, value })
382
- );
383
- validateItemInput(arrayKey, itemId, field, value);
384
- };
385
- const onItemSelectionChange = (arrayKey, itemId, field, value) => {
386
- const index = getIndex(String(arrayKey), itemId);
387
- if (index === void 0) return;
388
- const arr = state[arrayKey];
389
- const currentVal = getNestedValue(arr[index], field);
390
- const isString = typeof currentVal === "string" || currentVal === null;
391
- const fixedValue = typeof value === "string" || value === null ? value : isString ? Array.from(value)[0] || null : Array.from(value);
392
- setState(
393
- (prev) => handleArrayItemChange({
394
- state: prev,
395
- arrayKey,
396
- index,
397
- field,
398
- value: fixedValue
399
- })
400
- );
401
- validateItemInput(arrayKey, itemId, field, fixedValue);
402
- };
403
- const validateNestedInput = (dotPath, value) => {
404
- const ruleDef = getRule(dotPath);
405
- const rule = typeof ruleDef === "function" ? ruleDef(value, state) : ruleDef;
406
- const message = getMessage(dotPath);
407
- setErrors(
408
- (prev) => new Map(prev).set(dotPath, performValidations(value, rule, message))
409
- );
410
- };
411
- const onNestedBlur = (dotPath) => {
412
- const value = getNestedValue(state, dotPath);
413
- validateNestedInput(dotPath, value);
414
- if (touched.get(dotPath)) return;
415
- setTouched((prev) => new Map(prev).set(dotPath, true));
416
- };
417
- const onNestedValueChange = (dotPath, value) => {
418
- setState((prev) => setNestedValue(prev, dotPath, value));
419
- validateNestedInput(dotPath, value);
420
- };
421
- const onNestedSelectionChange = (dotPath, value) => {
422
- const currentVal = getNestedValue(state, dotPath);
423
- const isString = typeof currentVal === "string" || currentVal === null;
424
- const fixedValue = typeof value === "string" || value === null ? value : isString ? Array.from(value)[0] || null : Array.from(value);
425
- setState((prev) => setNestedValue(prev, dotPath, fixedValue));
426
- validateNestedInput(dotPath, fixedValue);
427
- };
428
- const on = {
429
- input: (...args) => {
430
- if (args.length === 1) {
431
- const id = args[0];
432
- const key = String(id);
433
- const isTopLevel = key in state;
434
- if (isTopLevel) {
435
- return {
436
- ...getUXProps(key),
437
- id: key,
438
- onBlur: () => onBlur(id),
439
- onValueChange: (v) => onValueChange(id, v),
440
- value: state[id]
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"
441
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;
442
411
  }
443
- return {
444
- ...getUXProps(key),
445
- id: key,
446
- onBlur: () => onNestedBlur(key),
447
- onValueChange: (v) => onNestedValueChange(key, v),
448
- value: getNestedValue(state, key)
449
- };
450
412
  }
451
- if (args.length === 2) {
452
- const [arrayKey2, index2] = args;
453
- const arr2 = state[arrayKey2];
454
- const value2 = arr2?.[index2];
455
- const compositeKey2 = getPrimitiveCompositeKey(String(arrayKey2), index2);
456
- return {
457
- ...getItemUXProps(String(arrayKey2), `@${index2}`, ""),
458
- id: compositeKey2,
459
- onBlur: () => {
460
- if (touched.get(compositeKey2)) return;
461
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
462
- },
463
- onValueChange: (v) => {
464
- setState((prev) => {
465
- const arr3 = [...prev[arrayKey2]];
466
- arr3[index2] = v;
467
- return { ...prev, [arrayKey2]: arr3 };
468
- });
469
- validateItemInput(arrayKey2, `@${index2}`, "", v);
470
- },
471
- value: value2
472
- };
413
+ return false;
414
+ },
415
+ []
416
+ );
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;
473
422
  }
474
- if (args.length === 4) {
475
- const [parentKey, parentId, field2, index2] = args;
476
- const parentIndex = getIndex(String(parentKey), parentId);
477
- const arr2 = state[parentKey];
478
- const nestedArr = parentIndex !== void 0 ? getNestedValue(arr2[parentIndex], field2) : void 0;
479
- const value2 = Array.isArray(nestedArr) ? nestedArr[index2] : void 0;
480
- const compositeKey2 = getNestedPrimitiveCompositeKey(
481
- String(parentKey),
482
- parentId,
483
- field2,
484
- index2
485
- );
486
- return {
487
- ...getItemUXProps(String(parentKey), parentId, `${field2}.@${index2}`),
488
- id: compositeKey2,
489
- onBlur: () => {
490
- if (touched.get(compositeKey2)) return;
491
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
492
- },
493
- onValueChange: (v) => {
494
- if (parentIndex === void 0) return;
495
- setState((prev) => {
496
- const parentArr = [...prev[parentKey]];
497
- const item = { ...parentArr[parentIndex] };
498
- const nestedArr2 = [...getNestedValue(item, field2) || []];
499
- nestedArr2[index2] = v;
500
- parentArr[parentIndex] = setNestedValue(item, field2, nestedArr2);
501
- return { ...prev, [parentKey]: parentArr };
502
- });
503
- const fieldPath = `${field2}.@${index2}`;
504
- validateItemInput(parentKey, parentId, fieldPath, v);
505
- },
506
- value: value2
423
+ setMetadata((prev) => {
424
+ const newMap = new Map(prev);
425
+ const currentMeta = newMap.get(compositeKey) || {
426
+ isTouched: false,
427
+ isInvalid: false,
428
+ errorMessage: ""
507
429
  };
508
- }
509
- const [arrayKey, itemId, field] = args;
510
- const index = getIndex(String(arrayKey), itemId);
511
- const arr = state[arrayKey];
512
- const value = index !== void 0 ? getNestedValue(arr[index], field) : void 0;
513
- const compositeKey = getItemCompositeKey(String(arrayKey), itemId, field);
514
- return {
515
- ...getItemUXProps(String(arrayKey), itemId, field),
516
- id: compositeKey,
517
- onBlur: () => onItemBlur(arrayKey, itemId, field),
518
- onValueChange: (v) => onItemValueChange(arrayKey, itemId, field, v),
519
- value
520
- };
430
+ newMap.set(compositeKey, {
431
+ ...currentMeta,
432
+ isInvalid: false,
433
+ errorMessage: ""
434
+ });
435
+ return newMap;
436
+ });
437
+ return false;
521
438
  },
522
- select: (...args) => {
523
- if (args.length === 1) {
524
- const id = args[0];
525
- const key = String(id);
526
- const isTopLevel = key in state;
527
- if (isTopLevel) {
528
- const isString3 = typeof state[id] === "string" || state[id] === null;
529
- return {
530
- ...getUXProps(key),
531
- id: key,
532
- onBlur: () => onBlur(id),
533
- onSelectionChange: (v) => onSelectionChange(
534
- id,
535
- !isString3 ? v : Array.from(v)[0] || null
536
- ),
537
- selectedKeys: state[id] === null ? [] : isString3 ? [state[id]] : state[id]
439
+ [getRule, runValidation, validationSchema]
440
+ );
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: ""
538
480
  };
539
- }
540
- const value2 = getNestedValue(state, key);
541
- const isString2 = typeof value2 === "string" || value2 === null;
542
- return {
543
- ...getUXProps(key),
544
- id: key,
545
- onBlur: () => onNestedBlur(key),
546
- onSelectionChange: (v) => onNestedSelectionChange(key, v),
547
- selectedKeys: value2 === null ? [] : isString2 ? [value2] : value2
548
- };
481
+ newMetadata.set(compositeKey, {
482
+ ...currentMeta,
483
+ isTouched: true,
484
+ isInvalid: true,
485
+ errorMessage: validationError.message
486
+ });
487
+ });
549
488
  }
550
- if (args.length === 2) {
551
- const [arrayKey2, index2] = args;
552
- const arr2 = state[arrayKey2];
553
- const value2 = arr2?.[index2];
554
- const compositeKey2 = getPrimitiveCompositeKey(String(arrayKey2), index2);
555
- return {
556
- ...getItemUXProps(String(arrayKey2), `@${index2}`, ""),
557
- id: compositeKey2,
558
- onBlur: () => {
559
- if (touched.get(compositeKey2)) return;
560
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
561
- },
562
- onSelectionChange: (v) => {
563
- const fixedValue = typeof v === "string" || v === null ? v : Array.from(v)[0] || null;
564
- setState((prev) => {
565
- const arr3 = [...prev[arrayKey2]];
566
- arr3[index2] = fixedValue;
567
- return { ...prev, [arrayKey2]: arr3 };
568
- });
569
- validateItemInput(arrayKey2, `@${index2}`, "", fixedValue);
570
- },
571
- selectedKeys: value2 === null ? [] : [value2]
572
- };
489
+ }
490
+ setMetadata(newMetadata);
491
+ return hasError;
492
+ }, [validationSchema, state, arrayIdentifiers]);
493
+ const handleFieldChange = (0, import_react2.useCallback)(
494
+ (resolution, newValue) => {
495
+ if (!resolution) return;
496
+ const {
497
+ type,
498
+ compositeKey,
499
+ fieldPath,
500
+ arrayKey,
501
+ index,
502
+ parentKey,
503
+ parentId,
504
+ nestedField
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;
573
510
  }
574
- if (args.length === 4) {
575
- const [parentKey, parentId, field2, index2] = args;
576
- const parentIndex = getIndex(String(parentKey), parentId);
577
- const arr2 = state[parentKey];
578
- const nestedArr = parentIndex !== void 0 ? getNestedValue(arr2[parentIndex], field2) : void 0;
579
- const value2 = Array.isArray(nestedArr) ? nestedArr[index2] : null;
580
- const compositeKey2 = getNestedPrimitiveCompositeKey(
581
- String(parentKey),
582
- parentId,
583
- field2,
584
- index2
585
- );
586
- return {
587
- ...getItemUXProps(String(parentKey), parentId, `${field2}.@${index2}`),
588
- id: compositeKey2,
589
- onBlur: () => {
590
- if (touched.get(compositeKey2)) return;
591
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
592
- },
593
- onSelectionChange: (v) => {
594
- if (parentIndex === void 0) return;
595
- const fixedValue = typeof v === "string" || v === null ? v : Array.from(v)[0] || null;
596
- setState((prev) => {
597
- const parentArr = [...prev[parentKey]];
598
- const item = { ...parentArr[parentIndex] };
599
- const nestedArr2 = [...getNestedValue(item, field2) || []];
600
- nestedArr2[index2] = fixedValue;
601
- parentArr[parentIndex] = setNestedValue(item, field2, nestedArr2);
602
- return { ...prev, [parentKey]: parentArr };
603
- });
604
- const fieldPath = `${field2}.@${index2}`;
605
- validateItemInput(parentKey, parentId, fieldPath, fixedValue);
606
- },
607
- selectedKeys: value2 === null ? [] : [value2]
608
- };
511
+ if (rule && rule.type === "string") {
512
+ try {
513
+ finalValue = rule.cast(newValue);
514
+ } catch {
515
+ }
609
516
  }
610
- const [arrayKey, itemId, field] = args;
611
- const index = getIndex(String(arrayKey), itemId);
612
- const arr = state[arrayKey];
613
- const value = index !== void 0 ? getNestedValue(arr[index], field) : null;
614
- const isString = typeof value === "string" || value === null;
615
- const compositeKey = getItemCompositeKey(String(arrayKey), itemId, field);
517
+ setState((prev) => {
518
+ if (type === "scalar" /* Scalar */) {
519
+ return handleNestedChange({
520
+ state: prev,
521
+ id: compositeKey,
522
+ value: finalValue,
523
+ hasNestedValues: compositeKey.includes(".")
524
+ });
525
+ }
526
+ if (type === "primitiveArray" /* PrimitiveArray */) {
527
+ const arr = [...prev[arrayKey]];
528
+ arr[index] = finalValue;
529
+ return { ...prev, [arrayKey]: arr };
530
+ }
531
+ if (type === "objectArray" /* ObjectArray */) {
532
+ return handleArrayItemChange({
533
+ state: prev,
534
+ arrayKey,
535
+ index,
536
+ field: resolution.field,
537
+ value: finalValue
538
+ });
539
+ }
540
+ if (type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
541
+ const pIndex = getIndex(parentKey, parentId);
542
+ if (pIndex === void 0) return prev;
543
+ const parentArr = [...prev[parentKey]];
544
+ const pItem = { ...parentArr[pIndex] };
545
+ const nestedArr = [...getNestedValue(pItem, nestedField) || []];
546
+ nestedArr[index] = finalValue;
547
+ pItem[nestedField] = nestedArr;
548
+ parentArr[pIndex] = pItem;
549
+ return { ...prev, [parentKey]: parentArr };
550
+ }
551
+ return prev;
552
+ });
553
+ validateField(compositeKey, fieldPath, finalValue);
554
+ },
555
+ [getIndex, validateField, getRule, validationSchema]
556
+ );
557
+ const createHandlers = (0, import_react2.useCallback)(
558
+ (resolution) => {
559
+ if (!resolution) return {};
560
+ const { compositeKey, fieldPath, value } = resolution;
561
+ const meta = metadataRef.current.get(compositeKey);
562
+ const isTouched = meta?.isTouched;
616
563
  return {
617
- ...getItemUXProps(String(arrayKey), itemId, field),
618
564
  id: compositeKey,
619
- onBlur: () => onItemBlur(arrayKey, itemId, field),
620
- onSelectionChange: (v) => onItemSelectionChange(arrayKey, itemId, field, v),
621
- selectedKeys: value === null ? [] : isString ? [value] : value
565
+ isInvalid: Boolean(isTouched && meta?.isInvalid),
566
+ errorMessage: isTouched ? meta?.errorMessage || "" : "",
567
+ onBlur: () => {
568
+ if (metadataRef.current.get(compositeKey)?.isTouched) return;
569
+ validateField(compositeKey, fieldPath, value);
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
+ });
580
+ }
622
581
  };
623
582
  },
624
- autocomplete: (...args) => {
625
- if (args.length === 1) {
626
- const id = args[0];
627
- const key = String(id);
628
- const isTopLevel = key in state;
629
- if (isTopLevel) {
630
- return {
631
- ...getUXProps(key),
632
- id: key,
633
- onBlur: () => onBlur(id),
634
- onSelectionChange: (v) => onSelectionChange(id, v),
635
- selectedKey: state[id]
636
- };
637
- }
583
+ [validateField]
584
+ );
585
+ const on = (0, import_react2.useMemo)(
586
+ () => ({
587
+ input: (...args) => {
588
+ const data = resolveFieldData(
589
+ args,
590
+ stateRef.current,
591
+ getIndex,
592
+ getNestedValue
593
+ );
594
+ if (!data) return {};
638
595
  return {
639
- ...getUXProps(key),
640
- id: key,
641
- onBlur: () => onNestedBlur(key),
642
- onSelectionChange: (v) => onNestedSelectionChange(key, v),
643
- selectedKey: getNestedValue(state, key)
596
+ ...createHandlers(data),
597
+ value: data.value,
598
+ onValueChange: (v) => handleFieldChange(data, v)
644
599
  };
645
- }
646
- if (args.length === 2) {
647
- const [arrayKey2, index2] = args;
648
- const arr2 = state[arrayKey2];
649
- const value2 = arr2?.[index2];
650
- const compositeKey2 = getPrimitiveCompositeKey(String(arrayKey2), index2);
600
+ },
601
+ select: (...args) => {
602
+ const data = resolveFieldData(
603
+ args,
604
+ stateRef.current,
605
+ getIndex,
606
+ getNestedValue
607
+ );
608
+ if (!data) return {};
609
+ const isString = typeof data.value === "string" || data.value === null;
651
610
  return {
652
- ...getItemUXProps(String(arrayKey2), `@${index2}`, ""),
653
- id: compositeKey2,
654
- onBlur: () => {
655
- if (touched.get(compositeKey2)) return;
656
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
657
- },
611
+ ...createHandlers(data),
612
+ selectedKeys: data.value === null ? [] : isString ? [data.value] : data.value,
658
613
  onSelectionChange: (v) => {
659
- const fixedValue = typeof v === "string" || v === null ? v : String(v);
660
- setState((prev) => {
661
- const arr3 = [...prev[arrayKey2]];
662
- arr3[index2] = fixedValue;
663
- return { ...prev, [arrayKey2]: arr3 };
664
- });
665
- validateItemInput(arrayKey2, `@${index2}`, "", fixedValue);
666
- },
667
- selectedKey: value2
614
+ const fixed = typeof v === "string" || v === null ? v : isString ? Array.from(v)[0] || null : Array.from(v);
615
+ handleFieldChange(data, fixed);
616
+ }
668
617
  };
669
- }
670
- if (args.length === 4) {
671
- const [parentKey, parentId, field2, index2] = args;
672
- const parentIndex = getIndex(String(parentKey), parentId);
673
- const arr2 = state[parentKey];
674
- const nestedArr = parentIndex !== void 0 ? getNestedValue(arr2[parentIndex], field2) : void 0;
675
- const value2 = Array.isArray(nestedArr) ? nestedArr[index2] : null;
676
- const compositeKey2 = getNestedPrimitiveCompositeKey(
677
- String(parentKey),
678
- parentId,
679
- field2,
680
- index2
618
+ },
619
+ autocomplete: (...args) => {
620
+ const data = resolveFieldData(
621
+ args,
622
+ stateRef.current,
623
+ getIndex,
624
+ getNestedValue
681
625
  );
626
+ if (!data) return {};
682
627
  return {
683
- ...getItemUXProps(String(parentKey), parentId, `${field2}.@${index2}`),
684
- id: compositeKey2,
685
- onBlur: () => {
686
- if (touched.get(compositeKey2)) return;
687
- setTouched((prev) => new Map(prev).set(compositeKey2, true));
688
- },
628
+ ...createHandlers(data),
629
+ selectedKey: data.value,
689
630
  onSelectionChange: (v) => {
690
- if (parentIndex === void 0) return;
691
- const fixedValue = typeof v === "string" || v === null ? v : String(v);
692
- setState((prev) => {
693
- const parentArr = [...prev[parentKey]];
694
- const item = { ...parentArr[parentIndex] };
695
- const nestedArr2 = [...getNestedValue(item, field2) || []];
696
- nestedArr2[index2] = fixedValue;
697
- parentArr[parentIndex] = setNestedValue(item, field2, nestedArr2);
698
- return { ...prev, [parentKey]: parentArr };
699
- });
700
- const fieldPath = `${field2}.@${index2}`;
701
- validateItemInput(parentKey, parentId, fieldPath, fixedValue);
702
- },
703
- selectedKey: value2
631
+ const fixed = typeof v === "string" || v === null ? v : String(v);
632
+ handleFieldChange(data, fixed);
633
+ }
704
634
  };
705
635
  }
706
- const [arrayKey, itemId, field] = args;
707
- const index = getIndex(String(arrayKey), itemId);
708
- const arr = state[arrayKey];
709
- const value = index !== void 0 ? getNestedValue(arr[index], field) : null;
710
- const compositeKey = getItemCompositeKey(String(arrayKey), itemId, field);
711
- return {
712
- ...getItemUXProps(String(arrayKey), itemId, field),
713
- id: compositeKey,
714
- onBlur: () => onItemBlur(arrayKey, itemId, field),
715
- onSelectionChange: (v) => onItemSelectionChange(arrayKey, itemId, field, v),
716
- selectedKey: value
717
- };
718
- }
719
- };
720
- return {
721
- onBlur,
722
- onValueChange,
723
- onSelectionChange,
724
- state,
725
- setState,
726
- touched,
727
- errors: errors2,
728
- on,
729
- helpers: {
636
+ }),
637
+ [createHandlers, getIndex, handleFieldChange]
638
+ );
639
+ const helpers = (0, import_react2.useMemo)(
640
+ () => ({
730
641
  addItem: (arrayKey, item, index) => {
731
642
  setState((prev) => {
732
643
  const arr = [...prev[arrayKey]];
733
- if (index === void 0) {
734
- arr.push(item);
735
- } else {
736
- arr.splice(index, 0, item);
737
- }
644
+ if (index === void 0) arr.push(item);
645
+ else arr.splice(index, 0, item);
738
646
  return { ...prev, [arrayKey]: arr };
739
647
  });
740
648
  },
741
649
  removeItem: (arrayKey, index) => {
742
- const itemIdKey = arrayIdentifiers?.[arrayKey] || "id";
743
- const item = state[arrayKey][index];
744
- const itemId = item?.[itemIdKey];
650
+ const currentArr = stateRef.current[arrayKey];
651
+ const item = currentArr[index];
652
+ const idKey = arrayIdentifiers?.[arrayKey] || "id";
653
+ const itemId = item?.[idKey];
745
654
  setState((prev) => {
746
655
  const arr = [...prev[arrayKey]];
747
656
  arr.splice(index, 1);
@@ -749,21 +658,28 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
749
658
  });
750
659
  if (itemId !== void 0) {
751
660
  const prefix = `${String(arrayKey)}.${itemId}.`;
752
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
753
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
661
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
754
662
  }
755
663
  },
756
664
  removeById: (arrayKey, itemId) => {
757
- const index = getIndex(String(arrayKey), itemId);
665
+ const index = getIndex(arrayKey, itemId);
758
666
  if (index !== void 0) {
759
- const arr = [...state[arrayKey]];
760
- arr.splice(index, 1);
761
- setState((prev) => ({ ...prev, [arrayKey]: arr }));
667
+ setState((prev) => {
668
+ const arr = [...prev[arrayKey]];
669
+ arr.splice(index, 1);
670
+ return { ...prev, [arrayKey]: arr };
671
+ });
762
672
  const prefix = `${String(arrayKey)}.${itemId}.`;
763
- setTouched((prev) => removeCompositeKeysByPrefix(prev, prefix));
764
- setErrors((prev) => removeCompositeKeysByPrefix(prev, prefix));
673
+ setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
765
674
  }
766
675
  },
676
+ updateItem: (arrayKey, index, value) => {
677
+ setState((prev) => {
678
+ const arr = [...prev[arrayKey]];
679
+ arr[index] = value;
680
+ return { ...prev, [arrayKey]: arr };
681
+ });
682
+ },
767
683
  moveItem: (arrayKey, from, to) => {
768
684
  setState((prev) => {
769
685
  const arr = [...prev[arrayKey]];
@@ -773,8 +689,8 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
773
689
  });
774
690
  },
775
691
  moveById: (arrayKey, fromId, toId) => {
776
- const fromIndex = getIndex(String(arrayKey), fromId);
777
- const toIndex = getIndex(String(arrayKey), toId);
692
+ const fromIndex = getIndex(arrayKey, fromId);
693
+ const toIndex = getIndex(arrayKey, toId);
778
694
  if (fromIndex !== void 0 && toIndex !== void 0) {
779
695
  setState((prev) => {
780
696
  const arr = [...prev[arrayKey]];
@@ -784,50 +700,117 @@ function useForm(initialState, { rules, messages, arrayIdentifiers } = {}) {
784
700
  });
785
701
  }
786
702
  },
787
- updateItem: (arrayKey, index, value) => {
788
- setState((prev) => {
789
- const arr = [...prev[arrayKey]];
790
- arr[index] = value;
791
- return { ...prev, [arrayKey]: arr };
792
- });
793
- },
794
703
  getItem: (arrayKey, itemId) => {
795
- const index = getIndex(String(arrayKey), itemId);
796
- if (index !== void 0) {
797
- return state[arrayKey][index];
798
- }
799
- return void 0;
704
+ const index = getIndex(arrayKey, itemId);
705
+ if (index === void 0) return void 0;
706
+ return stateRef.current[arrayKey][index];
800
707
  }
708
+ }),
709
+ [getIndex, arrayIdentifiers]
710
+ );
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
+ });
801
724
  },
802
- isDirty: JSON.stringify(state) !== JSON.stringify(initialState),
803
- hasInvalidValues: () => {
804
- const isInvalid = Array.from(errors2.values()).some((e) => e?.isInvalid);
805
- return isInvalid;
806
- },
807
- resetForm: (preservedKeys) => {
808
- setTouched(/* @__PURE__ */ new Map());
809
- setErrors(/* @__PURE__ */ new Map());
810
- setState(
811
- (prev) => preservedKeys === void 0 ? initialState : preservedKeys.reduce(
812
- (acc, key) => ({
813
- ...acc,
814
- [key]: prev[key]
815
- }),
816
- initialState
817
- )
725
+ [validateField]
726
+ );
727
+ const polymorphicOnValueChange = (0, import_react2.useCallback)(
728
+ (...args) => {
729
+ const value = args[args.length - 1];
730
+ const idArgs = args.slice(0, args.length - 1);
731
+ const data = resolveFieldData(
732
+ idArgs,
733
+ stateRef.current,
734
+ getIndex,
735
+ getNestedValue
818
736
  );
737
+ if (data) handleFieldChange(data, value);
819
738
  },
820
- resetTouched: (preservedKeys) => {
821
- setTouched(
822
- (prev) => preservedKeys === void 0 ? /* @__PURE__ */ new Map() : preservedKeys.reduce((acc, key) => {
823
- if (prev.has(String(key))) {
824
- acc.set(String(key), prev.get(String(key)));
825
- }
826
- return acc;
827
- }, /* @__PURE__ */ new Map())
828
- );
829
- }
830
- };
739
+ [getIndex, handleFieldChange]
740
+ );
741
+ const polymorphicOnSelectionChange = (0, import_react2.useCallback)(
742
+ (id, val) => {
743
+ const fixed = typeof val === "string" || val === null ? val : Array.from(val);
744
+ setState((prev) => handleNestedChange({ state: prev, id, value: fixed }));
745
+ validateField(String(id), String(id), fixed);
746
+ },
747
+ [validateField]
748
+ );
749
+ const onSubmit = (0, import_react2.useCallback)(
750
+ (fn) => (e) => {
751
+ e.preventDefault();
752
+ if (validateAll()) return;
753
+ fn(stateRef.current, e);
754
+ },
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
+ );
831
814
  }
832
815
  // Annotate the CommonJS export names for ESM import in node:
833
816
  0 && (module.exports = {