@stackcraftmx/calcita 0.32.1 → 0.47.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 +263 -2
- package/cli/packageVersions.js +12 -3
- package/cli/projectFiles.js +5 -2
- package/cli/templates/module/__Name__Page.test.jsx.tpl +24 -0
- package/cli/templates/project/README.md.tpl +14 -1
- package/cli/templates/project/src/app/appRouter.jsx.tpl +5 -2
- package/cli/templates/project/src/core/accountConnector.js.tpl +4 -2
- package/cli/templates/project/src/modules/auth/SignInPage.test.jsx.tpl +20 -0
- package/cli/templates/project/src/modules/home/HomePage.test.jsx.tpl +16 -0
- package/cli/templates/project/src/testing/browserGaps.js.tpl +70 -0
- package/cli/templates/project/src/testing/openScreen.jsx.tpl +58 -0
- package/cli/templates/project/src/testing/setup.js.tpl +25 -0
- package/cli/templates/project/vite.config.js.tpl +12 -0
- package/dist/DataTable/GoToPage.js +69 -13
- package/dist/DataTable/GoToPage.js.map +1 -1
- package/dist/DataTable/ServerTable.js +2 -0
- package/dist/DataTable/ServerTable.js.map +1 -1
- package/dist/DataTable/ServerTableFilterDrawer.js +52 -0
- package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -0
- package/dist/DataTable/filterContext.js.map +1 -1
- package/dist/DataTable/goToPageOptions.js +17 -0
- package/dist/DataTable/goToPageOptions.js.map +1 -0
- package/dist/date-pickers.js +28 -2
- package/dist/date-pickers.js.map +1 -1
- package/dist/datePickers/DateInput.js +15 -34
- package/dist/datePickers/DateInput.js.map +1 -1
- package/dist/datePickers/DateTimeInput.js +75 -0
- package/dist/datePickers/DateTimeInput.js.map +1 -0
- package/dist/datePickers/FormDateTimeField.js +12 -0
- package/dist/datePickers/FormDateTimeField.js.map +1 -0
- package/dist/datePickers/FormMonthField.js +12 -0
- package/dist/datePickers/FormMonthField.js.map +1 -0
- package/dist/datePickers/FormTimeField.js +12 -0
- package/dist/datePickers/FormTimeField.js.map +1 -0
- package/dist/datePickers/MonthInput.js +58 -0
- package/dist/datePickers/MonthInput.js.map +1 -0
- package/dist/datePickers/PickerFrame.js +27 -0
- package/dist/datePickers/PickerFrame.js.map +1 -0
- package/dist/datePickers/TimeInput.js +55 -0
- package/dist/datePickers/TimeInput.js.map +1 -0
- package/dist/datePickers/dateTimeRules.js +24 -0
- package/dist/datePickers/dateTimeRules.js.map +1 -0
- package/dist/datePickers/pickerValues.js +106 -0
- package/dist/datePickers/pickerValues.js.map +1 -0
- package/dist/datePickers/useCurrentMinute.js +28 -0
- package/dist/datePickers/useCurrentMinute.js.map +1 -0
- package/dist/datePickers/usePickerField.js +22 -0
- package/dist/datePickers/usePickerField.js.map +1 -0
- package/dist/dictionaries/dictionaries.js +3 -1
- package/dist/dictionaries/dictionaries.js.map +1 -1
- package/dist/forms/FormAttachmentsField.js +12 -0
- package/dist/forms/FormAttachmentsField.js.map +1 -0
- package/dist/forms/FormCheckboxGroupField.js +12 -0
- package/dist/forms/FormCheckboxGroupField.js.map +1 -0
- package/dist/forms/FormFileField.js +12 -0
- package/dist/forms/FormFileField.js.map +1 -0
- package/dist/forms/FormFileUploadField.js +12 -0
- package/dist/forms/FormFileUploadField.js.map +1 -0
- package/dist/forms/FormImageField.js +12 -0
- package/dist/forms/FormImageField.js.map +1 -0
- package/dist/forms/FormMaskedField.js +12 -0
- package/dist/forms/FormMaskedField.js.map +1 -0
- package/dist/forms/FormRepeatingFields.js +54 -0
- package/dist/forms/FormRepeatingFields.js.map +1 -0
- package/dist/forms/FormTransferListField.js +12 -0
- package/dist/forms/FormTransferListField.js.map +1 -0
- package/dist/forms/applyServerProblem.js +10 -3
- package/dist/forms/applyServerProblem.js.map +1 -1
- package/dist/forms/listRules.js +111 -0
- package/dist/forms/listRules.js.map +1 -0
- package/dist/forms/serverProblemFields.js +17 -0
- package/dist/forms/serverProblemFields.js.map +1 -1
- package/dist/forms.js +51 -29
- package/dist/forms.js.map +1 -1
- package/dist/hookForm/FormAttachmentsField.js +12 -0
- package/dist/hookForm/FormAttachmentsField.js.map +1 -0
- package/dist/hookForm/FormCheckboxGroupField.js +12 -0
- package/dist/hookForm/FormCheckboxGroupField.js.map +1 -0
- package/dist/hookForm/FormFileField.js +12 -0
- package/dist/hookForm/FormFileField.js.map +1 -0
- package/dist/hookForm/FormFileUploadField.js +12 -0
- package/dist/hookForm/FormFileUploadField.js.map +1 -0
- package/dist/hookForm/FormImageField.js +12 -0
- package/dist/hookForm/FormImageField.js.map +1 -0
- package/dist/hookForm/FormMaskedField.js +12 -0
- package/dist/hookForm/FormMaskedField.js.map +1 -0
- package/dist/hookForm/FormRepeatingFields.js +44 -0
- package/dist/hookForm/FormRepeatingFields.js.map +1 -0
- package/dist/hookForm/FormTransferListField.js +12 -0
- package/dist/hookForm/FormTransferListField.js.map +1 -0
- package/dist/hookForm/applyServerProblem.js +8 -3
- package/dist/hookForm/applyServerProblem.js.map +1 -1
- package/dist/index.js +188 -100
- package/dist/index.js.map +1 -1
- package/dist/inputs/CatalogInput.js +74 -7
- package/dist/inputs/CatalogInput.js.map +1 -1
- package/dist/inputs/CheckboxGroupInput.js +100 -0
- package/dist/inputs/CheckboxGroupInput.js.map +1 -0
- package/dist/inputs/MaskedInput.js +86 -0
- package/dist/inputs/MaskedInput.js.map +1 -0
- package/dist/inputs/NumberInput.js +12 -1
- package/dist/inputs/NumberInput.js.map +1 -1
- package/dist/inputs/RepeatingFields.js +177 -0
- package/dist/inputs/RepeatingFields.js.map +1 -0
- package/dist/inputs/SelectInput.js +43 -5
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/TransferListInput.js +215 -0
- package/dist/inputs/TransferListInput.js.map +1 -0
- package/dist/inputs/inputMasks.js +84 -0
- package/dist/inputs/inputMasks.js.map +1 -0
- package/dist/inputs/selectAllState.js +20 -0
- package/dist/inputs/selectAllState.js.map +1 -0
- package/dist/inputs/useRowKeys.js +26 -0
- package/dist/inputs/useRowKeys.js.map +1 -0
- package/dist/legal/CookieNotice.js +79 -0
- package/dist/legal/CookieNotice.js.map +1 -0
- package/dist/legal/TermsAcceptanceDialog.js +129 -0
- package/dist/legal/TermsAcceptanceDialog.js.map +1 -0
- package/dist/legal/consentStorage.js +18 -0
- package/dist/legal/consentStorage.js.map +1 -0
- package/dist/legal/useCookieConsent.js +17 -0
- package/dist/legal/useCookieConsent.js.map +1 -0
- package/dist/locales/en.js +233 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +233 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/mexico/CfdiSummary.js +81 -0
- package/dist/mexico/CfdiSummary.js.map +1 -0
- package/dist/mexico/EfirmaFields.js +167 -0
- package/dist/mexico/EfirmaFields.js.map +1 -0
- package/dist/mexico/certificateReader.js +79 -0
- package/dist/mexico/certificateReader.js.map +1 -0
- package/dist/mexico/cfdiReader.js +81 -0
- package/dist/mexico/cfdiReader.js.map +1 -0
- package/dist/mexico/derReader.js +81 -0
- package/dist/mexico/derReader.js.map +1 -0
- package/dist/mexico/efirmaKey.js +51 -0
- package/dist/mexico/efirmaKey.js.map +1 -0
- package/dist/mexico/mexicoIdentifiers.js +86 -0
- package/dist/mexico/mexicoIdentifiers.js.map +1 -0
- package/dist/mexico/mexicoRules.js +16 -0
- package/dist/mexico/mexicoRules.js.map +1 -0
- package/dist/mexico.js +32 -0
- package/dist/mexico.js.map +1 -0
- package/dist/react-hook-form.js +40 -17
- package/dist/react-hook-form.js.map +1 -1
- package/dist/rich-text.js +19 -0
- package/dist/rich-text.js.map +1 -0
- package/dist/richText/FormRichTextField.js +12 -0
- package/dist/richText/FormRichTextField.js.map +1 -0
- package/dist/richText/RichTextEditor.js +108 -0
- package/dist/richText/RichTextEditor.js.map +1 -0
- package/dist/richText/RichTextLinkPopover.js +57 -0
- package/dist/richText/RichTextLinkPopover.js.map +1 -0
- package/dist/richText/RichTextToolbar.js +189 -0
- package/dist/richText/RichTextToolbar.js.map +1 -0
- package/dist/richText/RichTextView.js +26 -0
- package/dist/richText/RichTextView.js.map +1 -0
- package/dist/richText/richTextContentSx.js +42 -0
- package/dist/richText/richTextContentSx.js.map +1 -0
- package/dist/richText/richTextExtensions.js +44 -0
- package/dist/richText/richTextExtensions.js.map +1 -0
- package/dist/richText/richTextRules.js +46 -0
- package/dist/richText/richTextRules.js.map +1 -0
- package/dist/security/SessionsCard.js +11 -7
- package/dist/security/SessionsCard.js.map +1 -1
- package/dist/table.js +2 -0
- package/dist/table.js.map +1 -1
- package/dist/theme/components/glassComponents.js +27 -0
- package/dist/theme/components/glassComponents.js.map +1 -1
- package/dist/theme/components/minimalComponents.js +12 -0
- package/dist/theme/components/minimalComponents.js.map +1 -1
- package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +21 -0
- package/dist/types/DataTable/filterContext.d.ts +2 -1
- package/dist/types/DataTable/goToPageOptions.d.ts +15 -0
- package/dist/types/DataTable/index.d.ts +1 -0
- package/dist/types/date-pickers.d.ts +10 -1
- package/dist/types/datePickers/DateInput.d.ts +6 -4
- package/dist/types/datePickers/DateTimeInput.d.ts +50 -0
- package/dist/types/datePickers/FormDateTimeField.d.ts +7 -0
- package/dist/types/datePickers/FormMonthField.d.ts +7 -0
- package/dist/types/datePickers/FormTimeField.d.ts +7 -0
- package/dist/types/datePickers/MonthInput.d.ts +39 -0
- package/dist/types/datePickers/PickerFrame.d.ts +22 -0
- package/dist/types/datePickers/TimeInput.d.ts +38 -0
- package/dist/types/datePickers/dateTimeRules.d.ts +31 -0
- package/dist/types/datePickers/pickerValues.d.ts +114 -0
- package/dist/types/datePickers/useCurrentMinute.d.ts +5 -0
- package/dist/types/datePickers/usePickerField.d.ts +24 -0
- package/dist/types/dictionaries/dictionaries.d.ts +6 -3
- package/dist/types/forms/FormAttachmentsField.d.ts +7 -0
- package/dist/types/forms/FormCheckboxGroupField.d.ts +7 -0
- package/dist/types/forms/FormFileField.d.ts +7 -0
- package/dist/types/forms/FormFileUploadField.d.ts +7 -0
- package/dist/types/forms/FormImageField.d.ts +7 -0
- package/dist/types/forms/FormMaskedField.d.ts +7 -0
- package/dist/types/forms/FormRepeatingFields.d.ts +25 -0
- package/dist/types/forms/FormTransferListField.d.ts +7 -0
- package/dist/types/forms/index.d.ts +10 -1
- package/dist/types/forms/listRules.d.ts +48 -0
- package/dist/types/forms/serverProblemFields.d.ts +13 -0
- package/dist/types/forms.d.ts +1 -1
- package/dist/types/hookForm/FormAttachmentsField.d.ts +8 -0
- package/dist/types/hookForm/FormCheckboxGroupField.d.ts +8 -0
- package/dist/types/hookForm/FormFileField.d.ts +8 -0
- package/dist/types/hookForm/FormFileUploadField.d.ts +8 -0
- package/dist/types/hookForm/FormImageField.d.ts +8 -0
- package/dist/types/hookForm/FormMaskedField.d.ts +9 -0
- package/dist/types/hookForm/FormRepeatingFields.d.ts +27 -0
- package/dist/types/hookForm/FormTransferListField.d.ts +8 -0
- package/dist/types/index.d.ts +25 -3
- package/dist/types/inputs/CatalogInput.d.ts +7 -1
- package/dist/types/inputs/CheckboxGroupInput.d.ts +39 -0
- package/dist/types/inputs/MaskedInput.d.ts +35 -0
- package/dist/types/inputs/RepeatingFields.d.ts +52 -0
- package/dist/types/inputs/SelectInput.d.ts +6 -1
- package/dist/types/inputs/TransferListInput.d.ts +43 -0
- package/dist/types/inputs/inputMasks.d.ts +52 -0
- package/dist/types/inputs/selectAllState.d.ts +11 -0
- package/dist/types/inputs/useRowKeys.d.ts +11 -0
- package/dist/types/legal/CookieNotice.d.ts +30 -0
- package/dist/types/legal/TermsAcceptanceDialog.d.ts +32 -0
- package/dist/types/legal/consentStorage.d.ts +16 -0
- package/dist/types/legal/useCookieConsent.d.ts +13 -0
- package/dist/types/locales/en.d.ts +232 -0
- package/dist/types/locales/es.d.ts +232 -0
- package/dist/types/mexico/CfdiSummary.d.ts +17 -0
- package/dist/types/mexico/EfirmaFields.d.ts +38 -0
- package/dist/types/mexico/certificateReader.d.ts +37 -0
- package/dist/types/mexico/cfdiReader.d.ts +95 -0
- package/dist/types/mexico/derReader.d.ts +54 -0
- package/dist/types/mexico/efirmaKey.d.ts +26 -0
- package/dist/types/mexico/mexicoIdentifiers.d.ts +61 -0
- package/dist/types/mexico/mexicoRules.d.ts +29 -0
- package/dist/types/mexico.d.ts +11 -0
- package/dist/types/react-hook-form.d.ts +10 -1
- package/dist/types/rich-text.d.ts +5 -0
- package/dist/types/richText/FormRichTextField.d.ts +7 -0
- package/dist/types/richText/RichTextEditor.d.ts +42 -0
- package/dist/types/richText/RichTextLinkPopover.d.ts +17 -0
- package/dist/types/richText/RichTextToolbar.d.ts +15 -0
- package/dist/types/richText/RichTextView.d.ts +13 -0
- package/dist/types/richText/richTextContentSx.d.ts +7 -0
- package/dist/types/richText/richTextExtensions.d.ts +15 -0
- package/dist/types/richText/richTextRules.d.ts +41 -0
- package/dist/types/table.d.ts +1 -1
- package/dist/types/ui/actions/ActionsMenu.d.ts +18 -3
- package/dist/types/ui/actions/CopyButton.d.ts +7 -4
- package/dist/types/ui/actions/tableRowText.d.ts +6 -0
- package/dist/types/ui/cards/RecordCard.d.ts +65 -0
- package/dist/types/ui/cards/RecordCardSkeleton.d.ts +17 -0
- package/dist/types/ui/countdown/Countdown.d.ts +31 -0
- package/dist/types/ui/countdown/countdownParts.d.ts +39 -0
- package/dist/types/ui/countdown/useCountdown.d.ts +14 -0
- package/dist/types/ui/documents/PdfViewerDialog.d.ts +21 -0
- package/dist/types/ui/filters/FilterDrawer.d.ts +34 -0
- package/dist/types/ui/filters/filterDrawerFields.d.ts +139 -0
- package/dist/types/ui/help/HelpButton.d.ts +15 -0
- package/dist/types/ui/help/HelpCarouselDialog.d.ts +35 -0
- package/dist/types/ui/help/useHelpCarousel.d.ts +21 -0
- package/dist/types/ui/index.d.ts +10 -0
- package/dist/types/ui/labels/IconBadge.d.ts +34 -0
- package/dist/types/ui/navigation/RouteTabs.d.ts +44 -0
- package/dist/types/ui/navigation/routeTabMatching.d.ts +27 -0
- package/dist/types/upload/AttachmentsInput.d.ts +62 -0
- package/dist/types/upload/FileChip.d.ts +18 -0
- package/dist/types/upload/FileDropzone.d.ts +3 -0
- package/dist/types/upload/FileInput.d.ts +48 -0
- package/dist/types/upload/FileUploadInput.d.ts +80 -0
- package/dist/types/upload/ImageInput.d.ts +53 -0
- package/dist/types/upload/TemplateDownloadButton.d.ts +39 -0
- package/dist/types/upload/fileAppearance.d.ts +8 -0
- package/dist/types/upload/fileRules.d.ts +38 -0
- package/dist/types/upload/transferProgress.d.ts +18 -0
- package/dist/types/upload/uploadMachine.d.ts +6 -2
- package/dist/types/upload/uploadWithProgress.d.ts +6 -2
- package/dist/types/upload/useFilePicker.d.ts +39 -0
- package/dist/ui/actions/ActionsMenu.js +98 -15
- package/dist/ui/actions/ActionsMenu.js.map +1 -1
- package/dist/ui/actions/CopyButton.js +31 -11
- package/dist/ui/actions/CopyButton.js.map +1 -1
- package/dist/ui/actions/tableRowText.js +7 -0
- package/dist/ui/actions/tableRowText.js.map +1 -0
- package/dist/ui/cards/RecordCard.js +145 -0
- package/dist/ui/cards/RecordCard.js.map +1 -0
- package/dist/ui/cards/RecordCardSkeleton.js +33 -0
- package/dist/ui/cards/RecordCardSkeleton.js.map +1 -0
- package/dist/ui/countdown/Countdown.js +38 -0
- package/dist/ui/countdown/Countdown.js.map +1 -0
- package/dist/ui/countdown/countdownParts.js +34 -0
- package/dist/ui/countdown/countdownParts.js.map +1 -0
- package/dist/ui/countdown/useCountdown.js +35 -0
- package/dist/ui/countdown/useCountdown.js.map +1 -0
- package/dist/ui/documents/PdfViewerDialog.js +81 -0
- package/dist/ui/documents/PdfViewerDialog.js.map +1 -0
- package/dist/ui/filters/FilterDrawer.js +211 -0
- package/dist/ui/filters/FilterDrawer.js.map +1 -0
- package/dist/ui/filters/filterDrawerFields.js +119 -0
- package/dist/ui/filters/filterDrawerFields.js.map +1 -0
- package/dist/ui/help/HelpButton.js +17 -0
- package/dist/ui/help/HelpButton.js.map +1 -0
- package/dist/ui/help/HelpCarouselDialog.js +154 -0
- package/dist/ui/help/HelpCarouselDialog.js.map +1 -0
- package/dist/ui/help/useHelpCarousel.js +25 -0
- package/dist/ui/help/useHelpCarousel.js.map +1 -0
- package/dist/ui/labels/IconBadge.js +82 -0
- package/dist/ui/labels/IconBadge.js.map +1 -0
- package/dist/ui/navigation/RouteTabs.js +75 -0
- package/dist/ui/navigation/RouteTabs.js.map +1 -0
- package/dist/ui/navigation/routeTabMatching.js +23 -0
- package/dist/ui/navigation/routeTabMatching.js.map +1 -0
- package/dist/upload/AttachmentsInput.js +127 -0
- package/dist/upload/AttachmentsInput.js.map +1 -0
- package/dist/upload/FileChip.js +27 -0
- package/dist/upload/FileChip.js.map +1 -0
- package/dist/upload/FileDropzone.js +19 -84
- package/dist/upload/FileDropzone.js.map +1 -1
- package/dist/upload/FileInput.js +112 -0
- package/dist/upload/FileInput.js.map +1 -0
- package/dist/upload/FileUploadInput.js +285 -0
- package/dist/upload/FileUploadInput.js.map +1 -0
- package/dist/upload/ImageInput.js +125 -0
- package/dist/upload/ImageInput.js.map +1 -0
- package/dist/upload/TemplateDownloadButton.js +67 -0
- package/dist/upload/TemplateDownloadButton.js.map +1 -0
- package/dist/upload/fileAppearance.js +21 -0
- package/dist/upload/fileAppearance.js.map +1 -0
- package/dist/upload/fileRules.js +27 -1
- package/dist/upload/fileRules.js.map +1 -1
- package/dist/upload/transferProgress.js +23 -0
- package/dist/upload/transferProgress.js.map +1 -0
- package/dist/upload/uploadMachine.js +8 -8
- package/dist/upload/uploadMachine.js.map +1 -1
- package/dist/upload/uploadWithProgress.js +1 -1
- package/dist/upload/uploadWithProgress.js.map +1 -1
- package/dist/upload/useFilePicker.js +101 -0
- package/dist/upload/useFilePicker.js.map +1 -0
- package/package.json +44 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listRules.js","sources":["../../src/forms/listRules.js"],"sourcesContent":["// Las reglas de yup para una lista de renglones (FormRepeatingFields), con sus mensajes en el idioma activo:\n//\n// uniqueInListRule('tiers', 'min_quantity') sin repetidos en esa columna («Ya está en el renglón 2»)\n// orderedInListRule('tiers', 'min_quantity') de menor a mayor («Debe ir entre 10 (renglón 1) y 50 (renglón 3)»)\n// listTotalAtMostRule('amount', (values) => values.credit_limit, {currency: 'MXN'})\n// lo que suman entre todos no pasa de un tope (con Money, sin floats)\n//\n// Yup.object({\n// tiers: Yup.array().of(Yup.object({\n// min_quantity: Yup.string().required().test(uniqueInListRule('tiers', 'min_quantity'))\n// .test(orderedInListRule('tiers', 'min_quantity')),\n// })),\n// split: Yup.array().of(…).test(listTotalAtMostRule('amount', (values) => values.credit_limit)),\n// })\n//\n// El repetido y el fuera de orden se marcan en SU renglón (no se borra lo que escribió la persona): el primero que aparece\n// se queda bien y el que repite dice con cuál choca. Un campo vacío pasa: que sea obligatorio lo dice required().\n//\n// Son objetos de .test() y no un Yup propio: el proyecto usa su copia de yup y aquí no se importa. Funcionan con formik y\n// con react-hook-form (yupResolver).\n//\n// Genérico del paquete: function (regla de la casa). Pruebas en listRules.test.js.\nimport {Money} from '@/money/money.js';\n\n/**\n * La lista completa desde la regla de un campo de un renglón: yup da en context.from los objetos de arriba (el renglón y\n * el que tiene la lista).\n *\n * @param {{from?: Array<{value: object}>}} context\n * @param {string} listName\n * @returns {object[]}\n */\nfunction rowsOf(context, listName) {\n return context.from?.[1]?.value?.[listName] ?? [];\n}\n\n/**\n * @param {unknown} value\n * @returns {number|null} el número, o null si viene vacío o no es número\n */\nfunction numberOf(value) {\n if (value === '' || value === null || value === undefined) {\n return null;\n }\n const number = Number(value);\n return Number.isFinite(number) ? number : null;\n}\n\n/**\n * Sin repetidos en una columna: el renglón que repite dice con cuál choca.\n *\n * @param {string} listName la lista en el formulario ('tiers')\n * @param {string} field la columna ('min_quantity')\n * @returns {import('yup').TestConfig<any, any>} para .test() de yup\n */\nexport function uniqueInListRule(listName, field) {\n return {\n name: 'uniqueInList',\n message: {key: 'validation:listDuplicate'},\n test: (value, context) => {\n if (value === '' || value === null || value === undefined) {\n return true;\n }\n const firstIndex = rowsOf(context, listName).findIndex((row) => String(row?.[field] ?? '') === String(value));\n if (firstIndex === -1 || firstIndex >= context.options.index) {\n return true;\n }\n return context.createError({message: {key: 'validation:listDuplicate', values: {row: firstIndex + 1}}});\n },\n };\n}\n\n/**\n * En orden por una columna, comparado con el renglón de arriba y el de abajo que tengan valor.\n *\n * @param {string} listName\n * @param {string} field\n * @param {{ascending?: boolean, allowEqual?: boolean, displayOf?: (text: string) => string}} [options] ascending: de menor\n * a mayor (por omisión); displayOf: cómo se dice el valor del vecino en el mensaje (p. ej. con %)\n * @returns {import('yup').TestConfig<any, any>} para .test() de yup\n */\nexport function orderedInListRule(listName, field, {ascending = true, allowEqual = false, displayOf = (text) => text} = {}) {\n const isInOrder = (lower, higher) => (allowEqual ? lower <= higher : lower < higher);\n return {\n name: 'orderedInList',\n message: {key: 'validation:listOrderBetween'},\n test: (value, context) => {\n const current = numberOf(value);\n if (current === null) {\n return true;\n }\n const rows = rowsOf(context, listName);\n const index = context.options.index;\n const hasValue = (rowIndex) => numberOf(rows[rowIndex]?.[field]) !== null;\n let previousIndex = index - 1;\n while (previousIndex >= 0 && !hasValue(previousIndex)) {\n previousIndex -= 1;\n }\n let nextIndex = index + 1;\n while (nextIndex < rows.length && !hasValue(nextIndex)) {\n nextIndex += 1;\n }\n const previous = previousIndex >= 0 ? numberOf(rows[previousIndex][field]) : null;\n const next = nextIndex < rows.length ? numberOf(rows[nextIndex][field]) : null;\n const fitsPrevious = previous === null || (ascending ? isInOrder(previous, current) : isInOrder(current, previous));\n const fitsNext = next === null || (ascending ? isInOrder(current, next) : isInOrder(next, current));\n if (fitsPrevious && fitsNext) {\n return true;\n }\n const values = {\n previous: previous === null ? '' : displayOf(String(rows[previousIndex][field])), previousRow: previousIndex + 1,\n next: next === null ? '' : displayOf(String(rows[nextIndex][field])), nextRow: nextIndex + 1,\n };\n // entre los dos si choca con ambos; si no, solo con el que choca (de menor a mayor: mayor que el de arriba)\n let key = 'validation:listOrderBetween';\n if (fitsNext) {\n key = ascending ? 'validation:listOrderAbovePrevious' : 'validation:listOrderBelowPrevious';\n } else if (fitsPrevious) {\n key = ascending ? 'validation:listOrderBelowNext' : 'validation:listOrderAboveNext';\n }\n return context.createError({message: {key, values}});\n },\n };\n}\n\n/**\n * Lo que suma una columna, con Money (sin errores de decimales). Los vacíos cuentan como cero y los que no son número no\n * cuentan (su propio campo ya lo dice).\n *\n * @param {object[]} rows\n * @param {string} field\n * @param {{currency?: string}} [options]\n * @returns {Money}\n */\nexport function listTotalOf(rows, field, {currency} = {}) {\n return (rows ?? []).reduce((total, row) => {\n try {\n const text = String(row?.[field] ?? '').trim();\n return text ? total.plus(Money.fromString(text, {currency})) : total;\n } catch {\n return total;\n }\n }, Money.zero({currency}));\n}\n\n/**\n * Lo que suman entre todos no pasa de un tope (el reparto de un presupuesto, de un límite de crédito). Va en la lista:\n * Yup.array().test(listTotalAtMostRule(…)); el mensaje sale abajo de la lista.\n *\n * @param {string} field la columna que se suma\n * @param {number|string|((parent: object) => number|string|null)} max el tope, o cómo sacarlo de los demás valores del\n * formulario (el límite que se escribió arriba)\n * @param {{currency?: string}} [options]\n * @returns {import('yup').TestConfig<any, any>} para .test() de yup\n */\nexport function listTotalAtMostRule(field, max, {currency} = {}) {\n return {\n name: 'listTotalAtMost',\n message: {key: 'validation:listTotalMax'},\n test: (rows, context) => {\n const maxText = typeof max === 'function' ? max(context.parent ?? {}) : max;\n if (maxText === '' || maxText === null || maxText === undefined) {\n return true;\n }\n let limit;\n try {\n limit = Money.fromString(String(maxText), {currency});\n } catch {\n return true;\n }\n const total = listTotalOf(Array.isArray(rows) ? rows : [], field, {currency});\n if (!total.isGreaterThan(limit)) {\n return true;\n }\n return context.createError({message: {key: 'validation:listTotalMax', values: {total: total.format(), max: limit.format()}}});\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -18,8 +18,25 @@ function formLevelMessageOf(errorsByField, formFieldNames, generalMessage) {
|
|
|
18
18
|
const hasFieldErrors = Object.keys(errorsByField ?? {}).length > 0;
|
|
19
19
|
return hasFieldErrors ? null : generalMessage || null;
|
|
20
20
|
}
|
|
21
|
+
const ROW_SEGMENT = /(^|\.)\d+(\.|$)|\[\d+\]/;
|
|
22
|
+
function splitRowFieldErrors(rawErrors, existsInForm) {
|
|
23
|
+
const rowFieldErrors = {};
|
|
24
|
+
const otherErrors = {};
|
|
25
|
+
if (!rawErrors || typeof rawErrors !== "object" || Array.isArray(rawErrors)) {
|
|
26
|
+
return { rowFieldErrors, otherErrors };
|
|
27
|
+
}
|
|
28
|
+
for (const [path, messages] of Object.entries(rawErrors)) {
|
|
29
|
+
if (ROW_SEGMENT.test(path) && existsInForm(path)) {
|
|
30
|
+
rowFieldErrors[path] = (Array.isArray(messages) ? messages : [messages]).map(String).join(" ");
|
|
31
|
+
} else {
|
|
32
|
+
otherErrors[path] = messages;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { rowFieldErrors, otherErrors };
|
|
36
|
+
}
|
|
21
37
|
export {
|
|
22
38
|
formLevelMessageOf,
|
|
39
|
+
splitRowFieldErrors,
|
|
23
40
|
splitServerFieldErrors
|
|
24
41
|
};
|
|
25
42
|
//# sourceMappingURL=serverProblemFields.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverProblemFields.js","sources":["../../src/forms/serverProblemFields.js"],"sourcesContent":["// Reparte los errores por campo de un 422 entre los campos que EXISTEN en el formulario y los que no.\n//\n// Lo que no tiene campo no se pierde: va al aviso de arriba del formulario. Un error invisible es peor que uno mal\n// colocado.\n//\n// Función pura sin imports (se prueba con node --test en serverProblemFields.test.js); la usan applyServerProblem y\n// las pantallas que pintan el aviso desde su máquina de estados.\n\n/**\n * @param {Record<string, string[]>} errorsByField lo que regresa fieldErrorsOf(problem)\n * @param {string[]} formFieldNames campos del formulario (Object.keys de sus valores iniciales)\n * @returns {{fieldErrors: Record<string, string>, unassignedMessages: string[]}}\n */\nexport function splitServerFieldErrors(errorsByField, formFieldNames) {\n const fieldErrors = {};\n const unassignedMessages = [];\n\n for (const [fieldName, messages] of Object.entries(errorsByField ?? {})) {\n if (formFieldNames.includes(fieldName)) {\n fieldErrors[fieldName] = messages.join(' ');\n } else {\n unassignedMessages.push(...messages);\n }\n }\n\n return {fieldErrors, unassignedMessages};\n}\n\n/**\n * Mensaje del aviso de arriba: lo que quedó sin campo, o el mensaje general si el error no trae errores por campo.\n * Si todo cayó en sus campos, no se repite arriba (null).\n *\n * @param {Record<string, string[]>} errorsByField\n * @param {string[]} formFieldNames\n * @param {string|null|undefined} generalMessage el message del ApiError (ya traducido)\n * @returns {string|null}\n */\nexport function formLevelMessageOf(errorsByField, formFieldNames, generalMessage) {\n const {unassignedMessages} = splitServerFieldErrors(errorsByField, formFieldNames);\n if (unassignedMessages.length > 0) {\n return unassignedMessages.join(' ');\n }\n const hasFieldErrors = Object.keys(errorsByField ?? {}).length > 0;\n return hasFieldErrors ? null : (generalMessage || null);\n}\n"],"names":[],"mappings":"AAaO,SAAS,uBAAuB,eAAe,gBAAgB;AAClE,QAAM,cAAc,CAAA;AACpB,QAAM,qBAAqB,CAAA;AAE3B,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,CAAA,CAAE,GAAG;AACrE,QAAI,eAAe,SAAS,SAAS,GAAG;AACpC,kBAAY,SAAS,IAAI,SAAS,KAAK,GAAG;AAAA,IAC9C,OAAO;AACH,yBAAmB,KAAK,GAAG,QAAQ;AAAA,IACvC;AAAA,EACJ;AAEA,SAAO,EAAC,aAAa,mBAAkB;AAC3C;AAWO,SAAS,mBAAmB,eAAe,gBAAgB,gBAAgB;AAC9E,QAAM,EAAC,mBAAkB,IAAI,uBAAuB,eAAe,cAAc;AACjF,MAAI,mBAAmB,SAAS,GAAG;AAC/B,WAAO,mBAAmB,KAAK,GAAG;AAAA,EACtC;AACA,QAAM,iBAAiB,OAAO,KAAK,iBAAiB,CAAA,CAAE,EAAE,SAAS;AACjE,SAAO,iBAAiB,OAAQ,kBAAkB;AACtD;"}
|
|
1
|
+
{"version":3,"file":"serverProblemFields.js","sources":["../../src/forms/serverProblemFields.js"],"sourcesContent":["// Reparte los errores por campo de un 422 entre los campos que EXISTEN en el formulario y los que no.\n//\n// Lo que no tiene campo no se pierde: va al aviso de arriba del formulario. Un error invisible es peor que uno mal\n// colocado.\n//\n// Función pura sin imports (se prueba con node --test en serverProblemFields.test.js); la usan applyServerProblem y\n// las pantallas que pintan el aviso desde su máquina de estados.\n\n/**\n * @param {Record<string, string[]>} errorsByField lo que regresa fieldErrorsOf(problem)\n * @param {string[]} formFieldNames campos del formulario (Object.keys de sus valores iniciales)\n * @returns {{fieldErrors: Record<string, string>, unassignedMessages: string[]}}\n */\nexport function splitServerFieldErrors(errorsByField, formFieldNames) {\n const fieldErrors = {};\n const unassignedMessages = [];\n\n for (const [fieldName, messages] of Object.entries(errorsByField ?? {})) {\n if (formFieldNames.includes(fieldName)) {\n fieldErrors[fieldName] = messages.join(' ');\n } else {\n unassignedMessages.push(...messages);\n }\n }\n\n return {fieldErrors, unassignedMessages};\n}\n\n/**\n * Mensaje del aviso de arriba: lo que quedó sin campo, o el mensaje general si el error no trae errores por campo.\n * Si todo cayó en sus campos, no se repite arriba (null).\n *\n * @param {Record<string, string[]>} errorsByField\n * @param {string[]} formFieldNames\n * @param {string|null|undefined} generalMessage el message del ApiError (ya traducido)\n * @returns {string|null}\n */\nexport function formLevelMessageOf(errorsByField, formFieldNames, generalMessage) {\n const {unassignedMessages} = splitServerFieldErrors(errorsByField, formFieldNames);\n if (unassignedMessages.length > 0) {\n return unassignedMessages.join(' ');\n }\n const hasFieldErrors = Object.keys(errorsByField ?? {}).length > 0;\n return hasFieldErrors ? null : (generalMessage || null);\n}\n\n// un renglón en la ruta del servidor: 'contacts.2.email' (Laravel) o 'contacts[2].email'\nconst ROW_SEGMENT = /(^|\\.)\\d+(\\.|$)|\\[\\d+\\]/;\n\n/**\n * Separa los errores de un 422 que son de un campo DENTRO de un renglón que el formulario sí tiene ('contacts.2.email'\n * con contacts[2] en los valores): esos van a su renglón con la ruta completa. Los demás siguen el camino de siempre\n * (fieldErrorsOf los reduce a su último nombre: 'rows.3.email' → 'email').\n *\n * @param {object|null|undefined} rawErrors problem.errors tal cual ({ruta: [mensajes]})\n * @param {(path: string) => boolean} existsInForm si esa ruta existe en los valores del formulario\n * @returns {{rowFieldErrors: Record<string, string>, otherErrors: Record<string, unknown>}}\n */\nexport function splitRowFieldErrors(rawErrors, existsInForm) {\n const rowFieldErrors = {};\n const otherErrors = {};\n if (!rawErrors || typeof rawErrors !== 'object' || Array.isArray(rawErrors)) {\n return {rowFieldErrors, otherErrors};\n }\n for (const [path, messages] of Object.entries(rawErrors)) {\n if (ROW_SEGMENT.test(path) && existsInForm(path)) {\n rowFieldErrors[path] = (Array.isArray(messages) ? messages : [messages]).map(String).join(' ');\n } else {\n otherErrors[path] = messages;\n }\n }\n return {rowFieldErrors, otherErrors};\n}\n\n"],"names":[],"mappings":"AAaO,SAAS,uBAAuB,eAAe,gBAAgB;AAClE,QAAM,cAAc,CAAA;AACpB,QAAM,qBAAqB,CAAA;AAE3B,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,CAAA,CAAE,GAAG;AACrE,QAAI,eAAe,SAAS,SAAS,GAAG;AACpC,kBAAY,SAAS,IAAI,SAAS,KAAK,GAAG;AAAA,IAC9C,OAAO;AACH,yBAAmB,KAAK,GAAG,QAAQ;AAAA,IACvC;AAAA,EACJ;AAEA,SAAO,EAAC,aAAa,mBAAkB;AAC3C;AAWO,SAAS,mBAAmB,eAAe,gBAAgB,gBAAgB;AAC9E,QAAM,EAAC,mBAAkB,IAAI,uBAAuB,eAAe,cAAc;AACjF,MAAI,mBAAmB,SAAS,GAAG;AAC/B,WAAO,mBAAmB,KAAK,GAAG;AAAA,EACtC;AACA,QAAM,iBAAiB,OAAO,KAAK,iBAAiB,CAAA,CAAE,EAAE,SAAS;AACjE,SAAO,iBAAiB,OAAQ,kBAAkB;AACtD;AAGA,MAAM,cAAc;AAWb,SAAS,oBAAoB,WAAW,cAAc;AACzD,QAAM,iBAAiB,CAAA;AACvB,QAAM,cAAc,CAAA;AACpB,MAAI,CAAC,aAAa,OAAO,cAAc,YAAY,MAAM,QAAQ,SAAS,GAAG;AACzE,WAAO,EAAC,gBAAgB,YAAW;AAAA,EACvC;AACA,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,SAAS,GAAG;AACtD,QAAI,YAAY,KAAK,IAAI,KAAK,aAAa,IAAI,GAAG;AAC9C,qBAAe,IAAI,KAAK,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ,GAAG,IAAI,MAAM,EAAE,KAAK,GAAG;AAAA,IACjG,OAAO;AACH,kBAAY,IAAI,IAAI;AAAA,IACxB;AAAA,EACJ;AACA,SAAO,EAAC,gBAAgB,YAAW;AACvC;"}
|
package/dist/forms.js
CHANGED
|
@@ -1,55 +1,77 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { FieldArray, Form, Formik, useField, useFormikContext } from "formik";
|
|
3
|
-
import { default as default2 } from "./forms/
|
|
4
|
-
import { default as default3 } from "./forms/
|
|
5
|
-
import { default as default4 } from "./forms/
|
|
6
|
-
import { default as default5 } from "./forms/
|
|
7
|
-
import { default as default6 } from "./forms/
|
|
8
|
-
import { default as default7 } from "./forms/
|
|
9
|
-
import { default as default8 } from "./forms/
|
|
10
|
-
import { default as default9 } from "./forms/
|
|
11
|
-
import { default as default10 } from "./forms/
|
|
12
|
-
import { default as default11 } from "./forms/
|
|
13
|
-
import { default as default12 } from "./forms/
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
3
|
+
import { default as default2 } from "./forms/FormAttachmentsField.js";
|
|
4
|
+
import { default as default3 } from "./forms/FormCatalogField.js";
|
|
5
|
+
import { default as default4 } from "./forms/FormCheckboxGroupField.js";
|
|
6
|
+
import { default as default5 } from "./forms/FormColorField.js";
|
|
7
|
+
import { default as default6 } from "./forms/FormFileField.js";
|
|
8
|
+
import { default as default7 } from "./forms/FormFileUploadField.js";
|
|
9
|
+
import { default as default8 } from "./forms/FormImageField.js";
|
|
10
|
+
import { default as default9 } from "./forms/FormMaskedField.js";
|
|
11
|
+
import { default as default10 } from "./forms/FormNumberField.js";
|
|
12
|
+
import { default as default11 } from "./forms/FormProblemAlert.js";
|
|
13
|
+
import { default as default12 } from "./forms/FormRepeatingFields.js";
|
|
14
|
+
import { default as default13 } from "./forms/FormTransferListField.js";
|
|
15
|
+
import { listTotalAtMostRule, listTotalOf, orderedInListRule, uniqueInListRule } from "./forms/listRules.js";
|
|
16
|
+
import { default as default14 } from "./forms/FormSelectField.js";
|
|
17
|
+
import { default as default15 } from "./forms/FormServerProblem.js";
|
|
18
|
+
import { default as default16 } from "./forms/FormTextField.js";
|
|
19
|
+
import { default as default17 } from "./forms/FormWizard.js";
|
|
20
|
+
import { default as default18 } from "./forms/auth/ChangePasswordForm.js";
|
|
21
|
+
import { default as default19 } from "./forms/auth/ForgotPasswordForm.js";
|
|
22
|
+
import { default as default20 } from "./forms/auth/SignInForm.js";
|
|
23
|
+
import { SECOND_STEP_METHOD, default as default21 } from "./forms/security/SecondStepForm.js";
|
|
24
|
+
import { default as default22 } from "./forms/security/TwoStepVerificationCard.js";
|
|
16
25
|
import { RECOVERY_CODE_PATTERN, TOTP_CODE_PATTERN, normalizeRecoveryCode, normalizeTotpCode } from "./forms/security/securityRules.js";
|
|
17
|
-
import { default as
|
|
26
|
+
import { default as default23 } from "./forms/SubmitButton.js";
|
|
18
27
|
import { applyServerProblem } from "./forms/applyServerProblem.js";
|
|
19
|
-
import { formLevelMessageOf, splitServerFieldErrors } from "./forms/serverProblemFields.js";
|
|
28
|
+
import { formLevelMessageOf, splitRowFieldErrors, splitServerFieldErrors } from "./forms/serverProblemFields.js";
|
|
20
29
|
import { useFormikField } from "./forms/useFormikField.js";
|
|
21
30
|
import { buildYupLocale } from "./forms/validation.js";
|
|
22
31
|
import * as Yup from "yup";
|
|
23
32
|
import { translateValidationMessage } from "./forms/validationMessages.js";
|
|
24
33
|
export {
|
|
25
|
-
|
|
34
|
+
default18 as ChangePasswordForm,
|
|
26
35
|
FieldArray,
|
|
27
|
-
|
|
36
|
+
default19 as ForgotPasswordForm,
|
|
28
37
|
Form,
|
|
29
|
-
default2 as
|
|
30
|
-
default3 as
|
|
31
|
-
default4 as
|
|
32
|
-
default5 as
|
|
33
|
-
default6 as
|
|
34
|
-
default7 as
|
|
35
|
-
default8 as
|
|
36
|
-
default9 as
|
|
38
|
+
default2 as FormAttachmentsField,
|
|
39
|
+
default3 as FormCatalogField,
|
|
40
|
+
default4 as FormCheckboxGroupField,
|
|
41
|
+
default5 as FormColorField,
|
|
42
|
+
default6 as FormFileField,
|
|
43
|
+
default7 as FormFileUploadField,
|
|
44
|
+
default8 as FormImageField,
|
|
45
|
+
default9 as FormMaskedField,
|
|
46
|
+
default10 as FormNumberField,
|
|
47
|
+
default11 as FormProblemAlert,
|
|
48
|
+
default12 as FormRepeatingFields,
|
|
49
|
+
default14 as FormSelectField,
|
|
50
|
+
default15 as FormServerProblem,
|
|
51
|
+
default16 as FormTextField,
|
|
52
|
+
default13 as FormTransferListField,
|
|
53
|
+
default17 as FormWizard,
|
|
37
54
|
Formik,
|
|
38
55
|
RECOVERY_CODE_PATTERN,
|
|
39
56
|
SECOND_STEP_METHOD,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
default21 as SecondStepForm,
|
|
58
|
+
default20 as SignInForm,
|
|
59
|
+
default23 as SubmitButton,
|
|
43
60
|
TOTP_CODE_PATTERN,
|
|
44
|
-
|
|
61
|
+
default22 as TwoStepVerificationCard,
|
|
45
62
|
Yup,
|
|
46
63
|
applyServerProblem,
|
|
47
64
|
buildYupLocale,
|
|
48
65
|
formLevelMessageOf,
|
|
66
|
+
listTotalAtMostRule,
|
|
67
|
+
listTotalOf,
|
|
49
68
|
normalizeRecoveryCode,
|
|
50
69
|
normalizeTotpCode,
|
|
70
|
+
orderedInListRule,
|
|
71
|
+
splitRowFieldErrors,
|
|
51
72
|
splitServerFieldErrors,
|
|
52
73
|
translateValidationMessage,
|
|
74
|
+
uniqueInListRule,
|
|
53
75
|
useField,
|
|
54
76
|
useFormikContext,
|
|
55
77
|
useFormikField
|
package/dist/forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"forms.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import AttachmentsInput from "../upload/AttachmentsInput.js";
|
|
5
|
+
function FormAttachmentsField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(AttachmentsInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormAttachmentsField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormAttachmentsField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormAttachmentsField.js","sources":["../../src/hookForm/FormAttachmentsField.jsx"],"sourcesContent":["// Campo de varios archivos de react-hook-form: AttachmentsInput (upload/) conectado a su campo con useController. Se ve y\n// se porta igual que el FormAttachmentsField de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport AttachmentsInput from '@/upload/AttachmentsInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/upload/AttachmentsInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormAttachmentsField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <AttachmentsInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,qBAAqB,EAAC,MAAM,SAAS,GAAG,cAAa;AACzE,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,kBAAA,EAAkB,GAAG,YAAa,GAAG,WAAA,CAAY;AAC7D;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import CheckboxGroupInput from "../inputs/CheckboxGroupInput.js";
|
|
5
|
+
function FormCheckboxGroupField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(CheckboxGroupInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormCheckboxGroupField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormCheckboxGroupField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormCheckboxGroupField.js","sources":["../../src/hookForm/FormCheckboxGroupField.jsx"],"sourcesContent":["// El grupo de casillas de react-hook-form: CheckboxGroupInput (inputs/) conectado con useController. Se ve y se porta\n// igual que el de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport CheckboxGroupInput from '@/inputs/CheckboxGroupInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/inputs/CheckboxGroupInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormCheckboxGroupField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <CheckboxGroupInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,uBAAuB,EAAC,MAAM,SAAS,GAAG,cAAa;AAC3E,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,oBAAA,EAAoB,GAAG,YAAa,GAAG,WAAA,CAAY;AAC/D;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import FileInput from "../upload/FileInput.js";
|
|
5
|
+
function FormFileField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(FileInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormFileField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormFileField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormFileField.js","sources":["../../src/hookForm/FormFileField.jsx"],"sourcesContent":["// Campo de un archivo de react-hook-form: FileInput (upload/) conectado a su campo con useController. Se ve y se porta igual\n// que el FormFileField de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport FileInput from '@/upload/FileInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/upload/FileInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormFileField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <FileInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,cAAc,EAAC,MAAM,SAAS,GAAG,cAAa;AAClE,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,WAAA,EAAW,GAAG,YAAa,GAAG,WAAA,CAAY;AACtD;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import FileUploadInput from "../upload/FileUploadInput.js";
|
|
5
|
+
function FormFileUploadField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(FileUploadInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormFileUploadField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormFileUploadField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormFileUploadField.js","sources":["../../src/hookForm/FormFileUploadField.jsx"],"sourcesContent":["// El cargador mini de react-hook-form: FileUploadInput (upload/) conectado a su campo con useController. Se ve y se porta\n// igual que el FormFileUploadField de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport FileUploadInput from '@/upload/FileUploadInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/upload/FileUploadInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormFileUploadField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <FileUploadInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,oBAAoB,EAAC,MAAM,SAAS,GAAG,cAAa;AACxE,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,iBAAA,EAAiB,GAAG,YAAa,GAAG,WAAA,CAAY;AAC5D;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import ImageInput from "../upload/ImageInput.js";
|
|
5
|
+
function FormImageField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(ImageInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormImageField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormImageField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormImageField.js","sources":["../../src/hookForm/FormImageField.jsx"],"sourcesContent":["// Campo de una imagen de react-hook-form: ImageInput (upload/) conectado a su campo con useController. Se ve y se porta igual\n// que el FormImageField de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport ImageInput from '@/upload/ImageInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/upload/ImageInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormImageField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <ImageInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,eAAe,EAAC,MAAM,SAAS,GAAG,cAAa;AACnE,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,YAAA,EAAY,GAAG,YAAa,GAAG,WAAA,CAAY;AACvD;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import MaskedInput from "../inputs/MaskedInput.js";
|
|
5
|
+
function FormMaskedField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(MaskedInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormMaskedField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormMaskedField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormMaskedField.js","sources":["../../src/hookForm/FormMaskedField.jsx"],"sourcesContent":["// Campo con máscara de react-hook-form: MaskedInput (inputs/) conectado a su campo. Al formulario llega el valor LIMPIO (sin\n// separadores, en mayúsculas): «5551234567», no «555 123 4567».\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport MaskedInput from '@/inputs/MaskedInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/inputs/MaskedInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props\n * las de MaskedInput (mask, label, helperText, placeholder…), sin value / onChange / onBlur / error; control: el de useForm,\n * si la pantalla no usa FormProvider\n */\nexport default function FormMaskedField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <MaskedInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAYA,SAAwB,gBAAgB,EAAC,MAAM,SAAS,GAAG,cAAa;AACpE,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,aAAA,EAAa,GAAG,YAAa,GAAG,WAAA,CAAY;AACxD;"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useFormContext, useFieldArray, useWatch, useFormState } from "react-hook-form";
|
|
4
|
+
import RepeatingFields from "../inputs/RepeatingFields.js";
|
|
5
|
+
const EMPTY_ROWS = Object.freeze([]);
|
|
6
|
+
function FormRepeatingFields({ name, control, emptyRow, renderRow, removeBlockedReason, confirmRemove, onAdd, onRemove, ...viewProps }) {
|
|
7
|
+
const formContext = useFormContext();
|
|
8
|
+
const formControl = control ?? formContext?.control;
|
|
9
|
+
const { fields, append, remove: removeAt, update } = useFieldArray({ name, control: formControl });
|
|
10
|
+
const rows = useWatch({ name, control: formControl }) ?? EMPTY_ROWS;
|
|
11
|
+
const { errors } = useFormState({ name, control: formControl });
|
|
12
|
+
const listErrors = name.split(".").reduce((branch, part) => branch?.[part], errors);
|
|
13
|
+
const listErrorMessage = listErrors?.root?.message ?? listErrors?.message;
|
|
14
|
+
return /* @__PURE__ */ jsx(
|
|
15
|
+
RepeatingFields,
|
|
16
|
+
{
|
|
17
|
+
...viewProps,
|
|
18
|
+
rowKeys: fields.map((field) => field.id),
|
|
19
|
+
renderRow: (index) => renderRow({ index, row: rows[index] ?? emptyRow, nameOf: (field) => `${name}.${index}.${field}` }),
|
|
20
|
+
onAdd: () => {
|
|
21
|
+
append({ ...emptyRow });
|
|
22
|
+
onAdd?.(fields.length);
|
|
23
|
+
},
|
|
24
|
+
onRemove: (index) => {
|
|
25
|
+
const removedRow = rows[index];
|
|
26
|
+
removeAt(index);
|
|
27
|
+
onRemove?.(removedRow, index);
|
|
28
|
+
},
|
|
29
|
+
onClear: (index) => {
|
|
30
|
+
const clearedRow = rows[index];
|
|
31
|
+
update(index, { ...emptyRow });
|
|
32
|
+
onRemove?.(clearedRow, index);
|
|
33
|
+
},
|
|
34
|
+
removeBlockedReasonOf: removeBlockedReason ? (index) => removeBlockedReason(rows[index], index) : void 0,
|
|
35
|
+
confirmRemoveOf: confirmRemove ? (index) => confirmRemove(rows[index], index) : void 0,
|
|
36
|
+
rowHasErrorOf: (index) => Boolean(listErrors?.[index]),
|
|
37
|
+
error: listErrorMessage
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
FormRepeatingFields as default
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=FormRepeatingFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormRepeatingFields.js","sources":["../../src/hookForm/FormRepeatingFields.jsx"],"sourcesContent":["// Renglones que se repiten en react-hook-form: RepeatingFields (inputs/) conectado con useFieldArray. Se usa igual que el\n// FormRepeatingFields de formik (@stackcraftmx/calcita/forms): name, emptyRow, renderRow con nameOf, y lo mismo para decidir\n// si un renglón se puede quitar.\n//\n// El error de toda la lista llega de yup (yupResolver lo pone en errors.<name>.root) o de las reglas del campo.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFieldArray, useFormContext, useFormState, useWatch} from 'react-hook-form';\n\nimport RepeatingFields from '@/inputs/RepeatingFields.jsx';\n\nconst EMPTY_ROWS = Object.freeze([]);\n\n/**\n * @param {{\n * name: string,\n * control?: object,\n * emptyRow: object,\n * renderRow: (row: {index: number, row: any, nameOf: (field: string) => string}) => import('react').ReactNode,\n * removeBlockedReason?: (row: any, index: number) => string|null,\n * confirmRemove?: (row: any, index: number) => boolean,\n * onAdd?: (index: number) => void,\n * onRemove?: (row: any, index: number) => void,\n * } & Omit<Parameters<typeof import('@/inputs/RepeatingFields.jsx').default>[0], 'rowKeys'|'renderRow'|'onAdd'|'onRemove'|'onClear'|'removeBlockedReasonOf'|'confirmRemoveOf'|'rowHasErrorOf'|'error'>} props\n * control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormRepeatingFields({name, control, emptyRow, renderRow, removeBlockedReason, confirmRemove, onAdd, onRemove, ...viewProps}) {\n const formContext = useFormContext();\n const formControl = control ?? formContext?.control;\n const {fields, append, remove: removeAt, update} = useFieldArray({name, control: formControl});\n const rows = useWatch({name, control: formControl}) ?? EMPTY_ROWS;\n const {errors} = useFormState({name, control: formControl});\n const listErrors = name.split('.').reduce((branch, part) => branch?.[part], errors);\n const listErrorMessage = listErrors?.root?.message ?? listErrors?.message;\n\n return (\n <RepeatingFields\n {...viewProps}\n rowKeys={fields.map((field) => field.id)}\n renderRow={(index) => renderRow({index, row: rows[index] ?? emptyRow, nameOf: (field) => `${name}.${index}.${field}`})}\n onAdd={() => {\n append({...emptyRow});\n onAdd?.(fields.length);\n }}\n onRemove={(index) => {\n const removedRow = rows[index];\n removeAt(index);\n onRemove?.(removedRow, index);\n }}\n onClear={(index) => {\n const clearedRow = rows[index];\n update(index, {...emptyRow});\n onRemove?.(clearedRow, index);\n }}\n removeBlockedReasonOf={removeBlockedReason ? (index) => removeBlockedReason(rows[index], index) : undefined}\n confirmRemoveOf={confirmRemove ? (index) => confirmRemove(rows[index], index) : undefined}\n rowHasErrorOf={(index) => Boolean(listErrors?.[index])}\n error={listErrorMessage}\n />\n );\n}\n"],"names":[],"mappings":";;;;AAWA,MAAM,aAAa,OAAO,OAAO,EAAE;AAenC,SAAwB,oBAAoB,EAAC,MAAM,SAAS,UAAU,WAAW,qBAAqB,eAAe,OAAO,UAAU,GAAG,UAAA,GAAY;AACjJ,QAAM,cAAc,eAAA;AACpB,QAAM,cAAc,WAAW,aAAa;AAC5C,QAAM,EAAC,QAAQ,QAAQ,QAAQ,UAAU,WAAU,cAAc,EAAC,MAAM,SAAS,YAAA,CAAY;AAC7F,QAAM,OAAO,SAAS,EAAC,MAAM,SAAS,YAAA,CAAY,KAAK;AACvD,QAAM,EAAC,WAAU,aAAa,EAAC,MAAM,SAAS,aAAY;AAC1D,QAAM,aAAa,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,QAAQ,SAAS,SAAS,IAAI,GAAG,MAAM;AAClF,QAAM,mBAAmB,YAAY,MAAM,WAAW,YAAY;AAElE,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACI,GAAG;AAAA,MACJ,SAAS,OAAO,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,MACvC,WAAW,CAAC,UAAU,UAAU,EAAC,OAAO,KAAK,KAAK,KAAK,KAAK,UAAU,QAAQ,CAAC,UAAU,GAAG,IAAI,IAAI,KAAK,IAAI,KAAK,IAAG;AAAA,MACrH,OAAO,MAAM;AACT,eAAO,EAAC,GAAG,UAAS;AACpB,gBAAQ,OAAO,MAAM;AAAA,MACzB;AAAA,MACA,UAAU,CAAC,UAAU;AACjB,cAAM,aAAa,KAAK,KAAK;AAC7B,iBAAS,KAAK;AACd,mBAAW,YAAY,KAAK;AAAA,MAChC;AAAA,MACA,SAAS,CAAC,UAAU;AAChB,cAAM,aAAa,KAAK,KAAK;AAC7B,eAAO,OAAO,EAAC,GAAG,UAAS;AAC3B,mBAAW,YAAY,KAAK;AAAA,MAChC;AAAA,MACA,uBAAuB,sBAAsB,CAAC,UAAU,oBAAoB,KAAK,KAAK,GAAG,KAAK,IAAI;AAAA,MAClG,iBAAiB,gBAAgB,CAAC,UAAU,cAAc,KAAK,KAAK,GAAG,KAAK,IAAI;AAAA,MAChF,eAAe,CAAC,UAAU,QAAQ,aAAa,KAAK,CAAC;AAAA,MACrD,OAAO;AAAA,IAAA;AAAA,EAAA;AAGnB;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useHookFormField } from "./useHookFormField.js";
|
|
4
|
+
import TransferListInput from "../inputs/TransferListInput.js";
|
|
5
|
+
function FormTransferListField({ name, control, ...inputProps }) {
|
|
6
|
+
const fieldProps = useHookFormField(name, control);
|
|
7
|
+
return /* @__PURE__ */ jsx(TransferListInput, { ...inputProps, ...fieldProps });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
FormTransferListField as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=FormTransferListField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormTransferListField.js","sources":["../../src/hookForm/FormTransferListField.jsx"],"sourcesContent":["// La lista de transferencia de react-hook-form: TransferListInput (inputs/) conectada con useController. Se ve y se porta\n// igual que la de formik (@stackcraftmx/calcita/forms).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useHookFormField} from '@/hookForm/useHookFormField.js';\nimport TransferListInput from '@/inputs/TransferListInput.jsx';\n\n/**\n * @param {{name: string, control?: object} & Omit<Parameters<typeof import('@/inputs/TransferListInput.jsx').default>[0], 'name'|'value'|'onChange'|'onBlur'|'error'>} props las del campo de la casa, sin\n * value / onChange / onBlur / error; control: el de useForm, si la pantalla no usa FormProvider\n */\nexport default function FormTransferListField({name, control, ...inputProps}) {\n const fieldProps = useHookFormField(name, control);\n return <TransferListInput {...inputProps} {...fieldProps} />;\n}\n"],"names":[],"mappings":";;;;AAWA,SAAwB,sBAAsB,EAAC,MAAM,SAAS,GAAG,cAAa;AAC1E,QAAM,aAAa,iBAAiB,MAAM,OAAO;AACjD,SAAO,oBAAC,mBAAA,EAAmB,GAAG,YAAa,GAAG,WAAA,CAAY;AAC9D;"}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import { splitServerFieldErrors, formLevelMessageOf } from "../forms/serverProblemFields.js";
|
|
1
|
+
import { splitRowFieldErrors, splitServerFieldErrors, formLevelMessageOf } from "../forms/serverProblemFields.js";
|
|
2
2
|
import { fieldErrorsOf } from "../problems.js";
|
|
3
3
|
const SERVER_PROBLEM_ROOT = "root.server";
|
|
4
4
|
const SERVER_ERROR_TYPE = "server";
|
|
5
5
|
function applyServerProblem(error, { setError, getValues }) {
|
|
6
|
-
const
|
|
6
|
+
const { rowFieldErrors, otherErrors } = splitRowFieldErrors(error?.problem?.errors, (path) => getValues(path) !== void 0);
|
|
7
|
+
for (const [path, message] of Object.entries(rowFieldErrors)) {
|
|
8
|
+
setError(path, { type: SERVER_ERROR_TYPE, message }, { shouldFocus: false });
|
|
9
|
+
}
|
|
10
|
+
const errorsByField = fieldErrorsOf(error?.problem ? { ...error.problem, errors: otherErrors } : null);
|
|
7
11
|
const formFieldNames = Object.keys(getValues() ?? {});
|
|
8
12
|
const { fieldErrors } = splitServerFieldErrors(errorsByField, formFieldNames);
|
|
9
13
|
for (const [fieldName, message] of Object.entries(fieldErrors)) {
|
|
10
14
|
setError(fieldName, { type: SERVER_ERROR_TYPE, message }, { shouldFocus: false });
|
|
11
15
|
}
|
|
12
|
-
const
|
|
16
|
+
const hasOnlyRowErrors = Object.keys(rowFieldErrors).length > 0 && Object.keys(errorsByField).length === 0;
|
|
17
|
+
const formLevelMessage = hasOnlyRowErrors ? null : formLevelMessageOf(errorsByField, formFieldNames, error?.message);
|
|
13
18
|
if (formLevelMessage) {
|
|
14
19
|
setError(SERVER_PROBLEM_ROOT, { type: SERVER_ERROR_TYPE, message: formLevelMessage });
|
|
15
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyServerProblem.js","sources":["../../src/hookForm/applyServerProblem.js"],"sourcesContent":["// Del error del servidor (RFC 9457) a react-hook-form, con las mismas reglas que el applyServerProblem de formik:\n// - el 422 trae `errors` por campo y cada uno se pinta EN su campo (setError);\n// - lo que no es de un campo (401, 409, 500, sin conexión) o el error de un campo que el formulario no tiene va al aviso\n// de arriba: errors.root.server, que pinta FormProblemAlert.\n//\n// const form = useForm({...});\n// const submit = form.handleSubmit(async (values) => {\n// try { await api.save(values); } catch (error) { applyServerProblem(error, form); }\n// });\n//\n// Función pura, no renderiza: function (regla de la casa).\nimport {formLevelMessageOf, splitServerFieldErrors} from '@/forms/serverProblemFields.js';\nimport {fieldErrorsOf} from '@/problems.js';\n\n/** Dónde queda el aviso de arriba en los errores de react-hook-form. */\nexport const SERVER_PROBLEM_ROOT = 'root.server';\nconst SERVER_ERROR_TYPE = 'server';\n\n/**\n * @param {unknown} error normalmente un ApiError (trae problem y message ya traducidos)\n * @param {{setError: Function, getValues: Function}} form lo que regresa useForm\n */\nexport function applyServerProblem(error, {setError, getValues}) {\n const errorsByField = fieldErrorsOf(error?.problem);\n const formFieldNames = Object.keys(getValues() ?? {});\n const {fieldErrors} = splitServerFieldErrors(errorsByField, formFieldNames);\n\n for (const [fieldName, message] of Object.entries(fieldErrors)) {\n setError(fieldName, {type: SERVER_ERROR_TYPE, message}, {shouldFocus: false});\n }\n\n const formLevelMessage = formLevelMessageOf(errorsByField, formFieldNames, error?.message);\n if (formLevelMessage) {\n setError(SERVER_PROBLEM_ROOT, {type: SERVER_ERROR_TYPE, message: formLevelMessage});\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"applyServerProblem.js","sources":["../../src/hookForm/applyServerProblem.js"],"sourcesContent":["// Del error del servidor (RFC 9457) a react-hook-form, con las mismas reglas que el applyServerProblem de formik:\n// - el 422 trae `errors` por campo y cada uno se pinta EN su campo (setError); el de un campo dentro de un renglón que el\n// formulario tiene ('contacts.2.email', FormRepeatingFields) va a ese renglón;\n// - lo que no es de un campo (401, 409, 500, sin conexión) o el error de un campo que el formulario no tiene va al aviso\n// de arriba: errors.root.server, que pinta FormProblemAlert.\n//\n// const form = useForm({...});\n// const submit = form.handleSubmit(async (values) => {\n// try { await api.save(values); } catch (error) { applyServerProblem(error, form); }\n// });\n//\n// Función pura, no renderiza: function (regla de la casa).\nimport {formLevelMessageOf, splitRowFieldErrors, splitServerFieldErrors} from '@/forms/serverProblemFields.js';\nimport {fieldErrorsOf} from '@/problems.js';\n\n/** Dónde queda el aviso de arriba en los errores de react-hook-form. */\nexport const SERVER_PROBLEM_ROOT = 'root.server';\nconst SERVER_ERROR_TYPE = 'server';\n\n/**\n * @param {unknown} error normalmente un ApiError (trae problem y message ya traducidos)\n * @param {{setError: Function, getValues: Function}} form lo que regresa useForm\n */\nexport function applyServerProblem(error, {setError, getValues}) {\n // primero los de un renglón ('contacts.2.email'), con su ruta completa; los demás, como siempre\n const {rowFieldErrors, otherErrors} = splitRowFieldErrors(error?.problem?.errors, (path) => getValues(path) !== undefined);\n for (const [path, message] of Object.entries(rowFieldErrors)) {\n setError(path, {type: SERVER_ERROR_TYPE, message}, {shouldFocus: false});\n }\n const errorsByField = fieldErrorsOf(error?.problem ? {...error.problem, errors: otherErrors} : null);\n const formFieldNames = Object.keys(getValues() ?? {});\n const {fieldErrors} = splitServerFieldErrors(errorsByField, formFieldNames);\n\n for (const [fieldName, message] of Object.entries(fieldErrors)) {\n setError(fieldName, {type: SERVER_ERROR_TYPE, message}, {shouldFocus: false});\n }\n\n // si todo cayó en renglones, tampoco se repite arriba\n const hasOnlyRowErrors = Object.keys(rowFieldErrors).length > 0 && Object.keys(errorsByField).length === 0;\n const formLevelMessage = hasOnlyRowErrors ? null : formLevelMessageOf(errorsByField, formFieldNames, error?.message);\n if (formLevelMessage) {\n setError(SERVER_PROBLEM_ROOT, {type: SERVER_ERROR_TYPE, message: formLevelMessage});\n }\n}\n"],"names":[],"mappings":";;AAgBY,MAAC,sBAAsB;AACnC,MAAM,oBAAoB;AAMnB,SAAS,mBAAmB,OAAO,EAAC,UAAU,UAAS,GAAG;AAE7D,QAAM,EAAC,gBAAgB,YAAW,IAAI,oBAAoB,OAAO,SAAS,QAAQ,CAAC,SAAS,UAAU,IAAI,MAAM,MAAS;AACzH,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC1D,aAAS,MAAM,EAAC,MAAM,mBAAmB,QAAO,GAAG,EAAC,aAAa,MAAK,CAAC;AAAA,EAC3E;AACA,QAAM,gBAAgB,cAAc,OAAO,UAAU,EAAC,GAAG,MAAM,SAAS,QAAQ,YAAW,IAAI,IAAI;AACnG,QAAM,iBAAiB,OAAO,KAAK,UAAS,KAAM,CAAA,CAAE;AACpD,QAAM,EAAC,YAAW,IAAI,uBAAuB,eAAe,cAAc;AAE1E,aAAW,CAAC,WAAW,OAAO,KAAK,OAAO,QAAQ,WAAW,GAAG;AAC5D,aAAS,WAAW,EAAC,MAAM,mBAAmB,QAAO,GAAG,EAAC,aAAa,MAAK,CAAC;AAAA,EAChF;AAGA,QAAM,mBAAmB,OAAO,KAAK,cAAc,EAAE,SAAS,KAAK,OAAO,KAAK,aAAa,EAAE,WAAW;AACzG,QAAM,mBAAmB,mBAAmB,OAAO,mBAAmB,eAAe,gBAAgB,OAAO,OAAO;AACnH,MAAI,kBAAkB;AAClB,aAAS,qBAAqB,EAAC,MAAM,mBAAmB,SAAS,iBAAgB,CAAC;AAAA,EACtF;AACJ;"}
|