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