@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.js
CHANGED
|
@@ -35,7 +35,7 @@ var NextUIError = class {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// src/hooks/useForm.tsx
|
|
38
|
-
var
|
|
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(
|
|
85
|
-
const result = new Map(
|
|
86
|
-
for (const key of
|
|
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
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
locale
|
|
189
|
-
|
|
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/
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
230
|
-
|
|
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
|
-
|
|
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
|
-
|
|
358
|
+
};
|
|
359
|
+
traverse(state, "");
|
|
360
|
+
return map;
|
|
242
361
|
}, [state, arrayIdentifiers]);
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
-
|
|
475
|
-
const
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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 (
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
...
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
...
|
|
653
|
-
|
|
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
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
...
|
|
684
|
-
|
|
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
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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
|
-
|
|
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
|
|
743
|
-
const item =
|
|
744
|
-
const
|
|
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
|
-
|
|
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(
|
|
665
|
+
const index = getIndex(arrayKey, itemId);
|
|
758
666
|
if (index !== void 0) {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
-
|
|
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(
|
|
777
|
-
const toIndex = getIndex(
|
|
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(
|
|
796
|
-
if (index
|
|
797
|
-
|
|
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
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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 = {
|