@stackcraftmx/calcita 0.47.0 → 0.52.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 +192 -13
- package/cli/calcita.js +17 -0
- package/cli/checkTexts.js +266 -0
- package/cli/packageVersions.js +6 -1
- package/cli/projectFiles.js +4 -2
- package/cli/templates/project/README.md.tpl +21 -1
- package/cli/templates/project/eslint.config.js.tpl +27 -0
- package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
- package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
- package/cli/templates/project/vite.config.js.tpl +8 -1
- package/dist/DataTable/AuditTrailDialog.js +3 -2
- package/dist/DataTable/AuditTrailDialog.js.map +1 -1
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
- package/dist/DataTable/EmptyState.js +3 -2
- package/dist/DataTable/EmptyState.js.map +1 -1
- package/dist/DataTable/FilterChips.js +3 -2
- package/dist/DataTable/FilterChips.js.map +1 -1
- package/dist/DataTable/GoToPage.js +3 -2
- package/dist/DataTable/GoToPage.js.map +1 -1
- package/dist/DataTable/ServerTable.js +95 -28
- package/dist/DataTable/ServerTable.js.map +1 -1
- package/dist/DataTable/ServerTableFilterDrawer.js +8 -3
- package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
- package/dist/DataTable/StackedCell.js +60 -0
- package/dist/DataTable/StackedCell.js.map +1 -0
- package/dist/DataTable/TableCardsView.js +88 -0
- package/dist/DataTable/TableCardsView.js.map +1 -0
- package/dist/DataTable/columnWidths.js +30 -0
- package/dist/DataTable/columnWidths.js.map +1 -0
- package/dist/DataTable/columns.js +47 -1
- package/dist/DataTable/columns.js.map +1 -1
- package/dist/DataTable/fixedColumns.js +24 -0
- package/dist/DataTable/fixedColumns.js.map +1 -0
- package/dist/DataTable/useTableView.js +29 -0
- package/dist/DataTable/useTableView.js.map +1 -0
- package/dist/access/PermissionMatrix.js +3 -2
- package/dist/access/PermissionMatrix.js.map +1 -1
- package/dist/account/AccountProvider.js +1 -1
- package/dist/account/AccountSecuritySection.js +3 -2
- package/dist/account/AccountSecuritySection.js.map +1 -1
- package/dist/account/DemoTotpCodeButton.js +3 -2
- package/dist/account/DemoTotpCodeButton.js.map +1 -1
- package/dist/account/ProfileScreen.js +3 -2
- package/dist/account/ProfileScreen.js.map +1 -1
- package/dist/account/SignInScreen.js +3 -2
- package/dist/account/SignInScreen.js.map +1 -1
- package/dist/appShell/AccountMenu.js +3 -2
- package/dist/appShell/AccountMenu.js.map +1 -1
- package/dist/appShell/AppLayout.js +3 -2
- package/dist/appShell/AppLayout.js.map +1 -1
- package/dist/appShell/AppearanceSettings.js +3 -2
- package/dist/appShell/AppearanceSettings.js.map +1 -1
- package/dist/appShell/AuthLayout.js +3 -2
- package/dist/appShell/AuthLayout.js.map +1 -1
- package/dist/appShell/BarActionButton.js +11 -4
- package/dist/appShell/BarActionButton.js.map +1 -1
- package/dist/appShell/BarActions.js +3 -2
- package/dist/appShell/BarActions.js.map +1 -1
- package/dist/appShell/BarCapsule.js +3 -2
- package/dist/appShell/BarCapsule.js.map +1 -1
- package/dist/appShell/BarSearch.js +3 -2
- package/dist/appShell/BarSearch.js.map +1 -1
- package/dist/appShell/HeaderTools.js +3 -2
- package/dist/appShell/HeaderTools.js.map +1 -1
- package/dist/appShell/MobileTabBar.js +3 -2
- package/dist/appShell/MobileTabBar.js.map +1 -1
- package/dist/appShell/SettingsMenu.js +3 -2
- package/dist/appShell/SettingsMenu.js.map +1 -1
- package/dist/appShell/SideMenu.js +3 -2
- package/dist/appShell/SideMenu.js.map +1 -1
- package/dist/appShell/SideMenuEntry.js +3 -2
- package/dist/appShell/SideMenuEntry.js.map +1 -1
- package/dist/appShell/SubmenuActionsMenu.js +3 -2
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
- package/dist/appShell/TabBarEditor.js +3 -2
- package/dist/appShell/TabBarEditor.js.map +1 -1
- package/dist/appShell/TopMenu.js +3 -2
- package/dist/appShell/TopMenu.js.map +1 -1
- package/dist/appShell/Wordmark.js +3 -2
- package/dist/appShell/Wordmark.js.map +1 -1
- package/dist/auth/PasswordChecklist.js +3 -2
- package/dist/auth/PasswordChecklist.js.map +1 -1
- package/dist/calendar/EventCalendar.js +3 -2
- package/dist/calendar/EventCalendar.js.map +1 -1
- package/dist/calendar/EventDetails.js +3 -2
- package/dist/calendar/EventDetails.js.map +1 -1
- package/dist/datePickers/DateInput.js +28 -22
- package/dist/datePickers/DateInput.js.map +1 -1
- package/dist/datePickers/DateTimeInput.js +33 -27
- package/dist/datePickers/DateTimeInput.js.map +1 -1
- package/dist/datePickers/MonthInput.js +27 -21
- package/dist/datePickers/MonthInput.js.map +1 -1
- package/dist/datePickers/TimeInput.js +26 -20
- package/dist/datePickers/TimeInput.js.map +1 -1
- package/dist/datePickers/usePickerField.js +5 -4
- package/dist/datePickers/usePickerField.js.map +1 -1
- package/dist/downloads/DownloadManager.js +3 -2
- package/dist/downloads/DownloadManager.js.map +1 -1
- package/dist/feedback/ConfirmDialog.js +3 -2
- package/dist/feedback/ConfirmDialog.js.map +1 -1
- package/dist/feedback/ModalWaiting.js +3 -2
- package/dist/feedback/ModalWaiting.js.map +1 -1
- package/dist/feedback/NewBuildNotice.js +3 -2
- package/dist/feedback/NewBuildNotice.js.map +1 -1
- package/dist/filepond/FileDropzone.js +3 -2
- package/dist/filepond/FileDropzone.js.map +1 -1
- package/dist/forms/FormProblemAlert.js +3 -2
- package/dist/forms/FormProblemAlert.js.map +1 -1
- package/dist/forms/FormWizard.js +21 -6
- package/dist/forms/FormWizard.js.map +1 -1
- package/dist/forms/SubmitButton.js +7 -2
- package/dist/forms/SubmitButton.js.map +1 -1
- package/dist/forms/auth/SignInForm.js +3 -2
- package/dist/forms/auth/SignInForm.js.map +1 -1
- package/dist/forms/fieldRules.js +30 -0
- package/dist/forms/fieldRules.js.map +1 -0
- package/dist/forms/security/SecondStepForm.js +3 -2
- package/dist/forms/security/SecondStepForm.js.map +1 -1
- package/dist/forms/security/TwoStepVerificationCard.js +3 -2
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
- package/dist/forms/useValidationText.js +18 -0
- package/dist/forms/useValidationText.js.map +1 -0
- package/dist/forms/validation.js +35 -31
- package/dist/forms/validation.js.map +1 -1
- package/dist/forms/validationMessages.js +64 -7
- package/dist/forms/validationMessages.js.map +1 -1
- package/dist/forms.js +3 -0
- package/dist/forms.js.map +1 -1
- package/dist/hookForm/FormProblemAlert.js +3 -2
- package/dist/hookForm/FormProblemAlert.js.map +1 -1
- package/dist/hookForm/FormWizard.js +19 -5
- package/dist/hookForm/FormWizard.js.map +1 -1
- package/dist/hookForm/SubmitButton.js +7 -2
- package/dist/hookForm/SubmitButton.js.map +1 -1
- package/dist/inbox/InboxLayout.js +3 -2
- package/dist/inbox/InboxLayout.js.map +1 -1
- package/dist/inbox/MessageList.js +3 -2
- package/dist/inbox/MessageList.js.map +1 -1
- package/dist/inbox/MessageView.js +3 -2
- package/dist/inbox/MessageView.js.map +1 -1
- package/dist/index.js +193 -163
- package/dist/index.js.map +1 -1
- package/dist/inputs/CatalogInput.js +32 -25
- package/dist/inputs/CatalogInput.js.map +1 -1
- package/dist/inputs/CheckboxGroupInput.js +8 -5
- package/dist/inputs/CheckboxGroupInput.js.map +1 -1
- package/dist/inputs/ColorInput.js +7 -4
- package/dist/inputs/ColorInput.js.map +1 -1
- package/dist/inputs/FieldFrame.js +10 -4
- package/dist/inputs/FieldFrame.js.map +1 -1
- package/dist/inputs/FormSection.js +1 -1
- package/dist/inputs/MaskedInput.js +1 -0
- package/dist/inputs/MaskedInput.js.map +1 -1
- package/dist/inputs/NumberInput.js +29 -24
- package/dist/inputs/NumberInput.js.map +1 -1
- package/dist/inputs/RepeatingFields.js +8 -5
- package/dist/inputs/RepeatingFields.js.map +1 -1
- package/dist/inputs/SelectInput.js +8 -5
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/TextInput.js +5 -3
- package/dist/inputs/TextInput.js.map +1 -1
- package/dist/inputs/TransferListInput.js +8 -5
- package/dist/inputs/TransferListInput.js.map +1 -1
- package/dist/inputs/WizardLayout.js +48 -19
- package/dist/inputs/WizardLayout.js.map +1 -1
- package/dist/inputs/useWizardSteps.js +36 -0
- package/dist/inputs/useWizardSteps.js.map +1 -0
- package/dist/inputs/wizardSteps.js +32 -0
- package/dist/inputs/wizardSteps.js.map +1 -0
- package/dist/kanban/KanbanBoard.js +3 -2
- package/dist/kanban/KanbanBoard.js.map +1 -1
- package/dist/legal/CookieNotice.js +3 -2
- package/dist/legal/CookieNotice.js.map +1 -1
- package/dist/legal/TermsAcceptanceDialog.js +3 -2
- package/dist/legal/TermsAcceptanceDialog.js.map +1 -1
- package/dist/locales/en.js +24 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +24 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/maps/MapView.js +3 -2
- package/dist/maps/MapView.js.map +1 -1
- package/dist/mexico/CfdiSummary.js +3 -2
- package/dist/mexico/CfdiSummary.js.map +1 -1
- package/dist/mexico/EfirmaFields.js +3 -2
- package/dist/mexico/EfirmaFields.js.map +1 -1
- package/dist/mexico/mexicoIdentifiers.js +5 -0
- package/dist/mexico/mexicoIdentifiers.js.map +1 -1
- package/dist/mexico/mexicoRules.js +9 -4
- package/dist/mexico/mexicoRules.js.map +1 -1
- package/dist/mexico.js +4 -2
- package/dist/pwa/InstallAppSetting.js +3 -2
- package/dist/pwa/InstallAppSetting.js.map +1 -1
- package/dist/pwa/InstallInstructionsDialog.js +3 -2
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
- package/dist/pwa/InstallPromptBanner.js +3 -2
- package/dist/pwa/InstallPromptBanner.js.map +1 -1
- package/dist/react-hook-form.js +3 -0
- package/dist/react-hook-form.js.map +1 -1
- package/dist/richText/RichTextEditor.js +7 -4
- package/dist/richText/RichTextEditor.js.map +1 -1
- package/dist/richText/RichTextView.js +3 -2
- package/dist/richText/RichTextView.js.map +1 -1
- package/dist/security/ActivityLog.js +3 -2
- package/dist/security/ActivityLog.js.map +1 -1
- package/dist/security/RecoveryCodesDialog.js +3 -2
- package/dist/security/RecoveryCodesDialog.js.map +1 -1
- package/dist/security/SessionsCard.js +3 -2
- package/dist/security/SessionsCard.js.map +1 -1
- package/dist/table.js +21 -2
- package/dist/table.js.map +1 -1
- package/dist/theme/themePieces.js +70 -4
- package/dist/theme/themePieces.js.map +1 -1
- package/dist/toolkit/ToolkitProvider.js +8 -1
- package/dist/toolkit/ToolkitProvider.js.map +1 -1
- package/dist/toolkit/browserNavigation.js +19 -4
- package/dist/toolkit/browserNavigation.js.map +1 -1
- package/dist/toolkit/combineTexts.js +32 -0
- package/dist/toolkit/combineTexts.js.map +1 -0
- package/dist/toolkit/hashNavigation.js +17 -3
- package/dist/toolkit/hashNavigation.js.map +1 -1
- package/dist/toolkit/navigationPaths.js +15 -0
- package/dist/toolkit/navigationPaths.js.map +1 -1
- package/dist/toolkit/pathIndex.js +66 -0
- package/dist/toolkit/pathIndex.js.map +1 -0
- package/dist/toolkit/toolkitSettings.js +19 -1
- package/dist/toolkit/toolkitSettings.js.map +1 -1
- package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
- package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
- package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
- package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
- package/dist/types/DataTable/EmptyState.d.ts +6 -9
- package/dist/types/DataTable/FilterChips.d.ts +6 -11
- package/dist/types/DataTable/GoToPage.d.ts +6 -9
- package/dist/types/DataTable/ServerTable.d.ts +16 -80
- package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +6 -13
- package/dist/types/DataTable/StackedCell.d.ts +12 -0
- package/dist/types/DataTable/TableCardsView.d.ts +27 -0
- package/dist/types/DataTable/columnWidths.d.ts +21 -0
- package/dist/types/DataTable/columns.d.ts +111 -0
- package/dist/types/DataTable/fixedColumns.d.ts +29 -0
- package/dist/types/DataTable/index.d.ts +6 -1
- package/dist/types/DataTable/useTableView.d.ts +22 -0
- package/dist/types/access/PermissionMatrix.d.ts +6 -10
- package/dist/types/account/AccountSecuritySection.d.ts +6 -7
- package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
- package/dist/types/account/ProfileScreen.d.ts +6 -18
- package/dist/types/account/SignInScreen.d.ts +6 -13
- package/dist/types/appShell/AccountMenu.d.ts +6 -11
- package/dist/types/appShell/AppLayout.d.ts +3 -40
- package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
- package/dist/types/appShell/AuthLayout.d.ts +3 -11
- package/dist/types/appShell/BarActionButton.d.ts +7 -10
- package/dist/types/appShell/BarActions.d.ts +6 -15
- package/dist/types/appShell/BarCapsule.d.ts +6 -9
- package/dist/types/appShell/BarSearch.d.ts +6 -15
- package/dist/types/appShell/HeaderTools.d.ts +6 -16
- package/dist/types/appShell/MobileTabBar.d.ts +6 -13
- package/dist/types/appShell/SettingsMenu.d.ts +6 -10
- package/dist/types/appShell/SideMenu.d.ts +6 -20
- package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
- package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
- package/dist/types/appShell/TabBarEditor.d.ts +6 -9
- package/dist/types/appShell/TopMenu.d.ts +6 -5
- package/dist/types/appShell/Wordmark.d.ts +6 -7
- package/dist/types/auth/PasswordChecklist.d.ts +6 -9
- package/dist/types/calendar/EventCalendar.d.ts +6 -23
- package/dist/types/calendar/EventDetails.d.ts +6 -10
- package/dist/types/datePickers/DateInput.d.ts +7 -22
- package/dist/types/datePickers/DateTimeInput.d.ts +7 -27
- package/dist/types/datePickers/MonthInput.d.ts +7 -21
- package/dist/types/datePickers/TimeInput.d.ts +7 -21
- package/dist/types/datePickers/usePickerField.d.ts +5 -1
- package/dist/types/downloads/DownloadManager.d.ts +6 -6
- package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
- package/dist/types/feedback/ModalWaiting.d.ts +6 -9
- package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
- package/dist/types/filepond/FileDropzone.d.ts +6 -29
- package/dist/types/forms/FormProblemAlert.d.ts +6 -5
- package/dist/types/forms/FormWizard.d.ts +12 -1
- package/dist/types/forms/SubmitButton.d.ts +6 -6
- package/dist/types/forms/auth/SignInForm.d.ts +6 -11
- package/dist/types/forms/fieldRules.d.ts +44 -0
- package/dist/types/forms/index.d.ts +1 -0
- package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
- package/dist/types/forms/useValidationText.d.ts +12 -0
- package/dist/types/forms/validation.d.ts +117 -174
- package/dist/types/forms/validationMessages.d.ts +54 -6
- package/dist/types/forms.d.ts +1 -1
- package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
- package/dist/types/hookForm/FormWizard.d.ts +12 -1
- package/dist/types/hookForm/SubmitButton.d.ts +6 -13
- package/dist/types/inbox/InboxLayout.d.ts +6 -17
- package/dist/types/inbox/MessageList.d.ts +6 -18
- package/dist/types/inbox/MessageView.d.ts +6 -14
- package/dist/types/index.d.ts +10 -2
- package/dist/types/inputs/CatalogInput.d.ts +7 -24
- package/dist/types/inputs/CheckboxGroupInput.d.ts +7 -18
- package/dist/types/inputs/ColorInput.d.ts +7 -16
- package/dist/types/inputs/FieldFrame.d.ts +6 -10
- package/dist/types/inputs/MaskedInput.d.ts +3 -0
- package/dist/types/inputs/NumberInput.d.ts +7 -20
- package/dist/types/inputs/RepeatingFields.d.ts +7 -28
- package/dist/types/inputs/SelectInput.d.ts +7 -20
- package/dist/types/inputs/TextInput.d.ts +3 -0
- package/dist/types/inputs/TransferListInput.d.ts +7 -20
- package/dist/types/inputs/WizardLayout.d.ts +11 -21
- package/dist/types/inputs/useWizardSteps.d.ts +23 -0
- package/dist/types/inputs/wizardSteps.d.ts +65 -0
- package/dist/types/kanban/KanbanBoard.d.ts +6 -25
- package/dist/types/legal/CookieNotice.d.ts +6 -16
- package/dist/types/legal/TermsAcceptanceDialog.d.ts +6 -18
- package/dist/types/locales/en.d.ts +24 -0
- package/dist/types/locales/es.d.ts +24 -0
- package/dist/types/maps/MapView.d.ts +6 -17
- package/dist/types/mexico/CfdiSummary.d.ts +6 -11
- package/dist/types/mexico/EfirmaFields.d.ts +6 -16
- package/dist/types/mexico/mexicoIdentifiers.d.ts +7 -0
- package/dist/types/mexico/mexicoRules.d.ts +19 -3
- package/dist/types/mexico.d.ts +2 -2
- package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
- package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
- package/dist/types/react-hook-form.d.ts +1 -0
- package/dist/types/richText/RichTextEditor.d.ts +7 -22
- package/dist/types/richText/RichTextView.d.ts +6 -9
- package/dist/types/security/ActivityLog.d.ts +6 -9
- package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
- package/dist/types/security/SessionsCard.d.ts +6 -11
- package/dist/types/table.d.ts +3 -1
- package/dist/types/theme/themePieces.d.ts +55 -3
- package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
- package/dist/types/toolkit/browserNavigation.d.ts +7 -3
- package/dist/types/toolkit/combineTexts.d.ts +6 -0
- package/dist/types/toolkit/hashNavigation.d.ts +4 -2
- package/dist/types/toolkit/navigationPaths.d.ts +35 -0
- package/dist/types/toolkit/pathIndex.d.ts +27 -0
- package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
- package/dist/types/ui/actions/ActionsMenu.d.ts +9 -11
- package/dist/types/ui/actions/CopyButton.d.ts +6 -12
- package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
- package/dist/types/ui/actions/SecretField.d.ts +6 -11
- package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
- package/dist/types/ui/cards/RecordCard.d.ts +16 -29
- package/dist/types/ui/cards/RecordCardSkeleton.d.ts +6 -11
- package/dist/types/ui/countdown/Countdown.d.ts +6 -15
- package/dist/types/ui/documents/PdfViewerDialog.d.ts +6 -13
- package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
- package/dist/types/ui/filters/FilterDrawer.d.ts +6 -17
- package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
- package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
- package/dist/types/ui/help/HelpButton.d.ts +6 -10
- package/dist/types/ui/help/HelpCarouselDialog.d.ts +6 -14
- package/dist/types/ui/index.d.ts +1 -1
- package/dist/types/ui/labels/MarkedText.d.ts +10 -0
- package/dist/types/ui/labels/Tag.d.ts +6 -12
- package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
- package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
- package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
- package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
- package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
- package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
- package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
- package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
- package/dist/types/ui/layout/PageHeader.d.ts +6 -10
- package/dist/types/ui/layout/PageHeading.d.ts +6 -11
- package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
- package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
- package/dist/types/ui/layout/SectionCard.d.ts +6 -8
- package/dist/types/ui/metrics/BarList.d.ts +6 -12
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
- package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
- package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
- package/dist/types/ui/metrics/LineChart.d.ts +6 -20
- package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
- package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
- package/dist/types/ui/metrics/chartParts.d.ts +15 -30
- package/dist/types/ui/navigation/BackButton.d.ts +7 -9
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
- package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
- package/dist/types/ui/navigation/RouteTabs.d.ts +7 -12
- package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
- package/dist/types/upload/AttachmentsInput.d.ts +11 -1
- package/dist/types/upload/FileDropzone.d.ts +6 -21
- package/dist/types/upload/FileInput.d.ts +7 -24
- package/dist/types/upload/FileUploadInput.d.ts +7 -31
- package/dist/types/upload/ImageInput.d.ts +7 -25
- package/dist/types/upload/TemplateDownloadButton.d.ts +6 -18
- package/dist/ui/actions/ActionsMenu.js +14 -5
- package/dist/ui/actions/ActionsMenu.js.map +1 -1
- package/dist/ui/actions/CopyButton.js +8 -3
- package/dist/ui/actions/CopyButton.js.map +1 -1
- package/dist/ui/actions/DownloadMenu.js +3 -2
- package/dist/ui/actions/DownloadMenu.js.map +1 -1
- package/dist/ui/actions/SecretField.js +8 -3
- package/dist/ui/actions/SecretField.js.map +1 -1
- package/dist/ui/actions/SelectionActions.js +3 -2
- package/dist/ui/actions/SelectionActions.js.map +1 -1
- package/dist/ui/cards/RecordCard.js +10 -5
- package/dist/ui/cards/RecordCard.js.map +1 -1
- package/dist/ui/cards/RecordCardSkeleton.js +8 -3
- package/dist/ui/cards/RecordCardSkeleton.js.map +1 -1
- package/dist/ui/countdown/Countdown.js +3 -2
- package/dist/ui/countdown/Countdown.js.map +1 -1
- package/dist/ui/documents/PdfViewerDialog.js +3 -2
- package/dist/ui/documents/PdfViewerDialog.js.map +1 -1
- package/dist/ui/filters/DateRangeFilter.js +3 -2
- package/dist/ui/filters/DateRangeFilter.js.map +1 -1
- package/dist/ui/filters/FilterDrawer.js +3 -2
- package/dist/ui/filters/FilterDrawer.js.map +1 -1
- package/dist/ui/filters/PeriodRangeSelector.js +3 -2
- package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
- package/dist/ui/filters/QuickFilters.js +3 -2
- package/dist/ui/filters/QuickFilters.js.map +1 -1
- package/dist/ui/help/HelpButton.js +8 -3
- package/dist/ui/help/HelpButton.js.map +1 -1
- package/dist/ui/help/HelpCarouselDialog.js +3 -2
- package/dist/ui/help/HelpCarouselDialog.js.map +1 -1
- package/dist/ui/labels/MarkedText.js +31 -0
- package/dist/ui/labels/MarkedText.js.map +1 -0
- package/dist/ui/labels/Tag.js +3 -2
- package/dist/ui/labels/Tag.js.map +1 -1
- package/dist/ui/labels/markedTextPieces.js +64 -0
- package/dist/ui/labels/markedTextPieces.js.map +1 -0
- package/dist/ui/layout/CollapsibleSection.js +3 -2
- package/dist/ui/layout/CollapsibleSection.js.map +1 -1
- package/dist/ui/layout/ContentDialog.js +3 -2
- package/dist/ui/layout/ContentDialog.js.map +1 -1
- package/dist/ui/layout/DefinitionList.js +3 -2
- package/dist/ui/layout/DefinitionList.js.map +1 -1
- package/dist/ui/layout/DetailHeader.js +3 -2
- package/dist/ui/layout/DetailHeader.js.map +1 -1
- package/dist/ui/layout/ErrorPage.js +3 -2
- package/dist/ui/layout/ErrorPage.js.map +1 -1
- package/dist/ui/layout/FullPageLoader.js +3 -2
- package/dist/ui/layout/FullPageLoader.js.map +1 -1
- package/dist/ui/layout/GlassPanel.js +3 -2
- package/dist/ui/layout/GlassPanel.js.map +1 -1
- package/dist/ui/layout/PageHeader.js +3 -2
- package/dist/ui/layout/PageHeader.js.map +1 -1
- package/dist/ui/layout/PageHeading.js +3 -2
- package/dist/ui/layout/PageHeading.js.map +1 -1
- package/dist/ui/layout/ProfileHeader.js +3 -2
- package/dist/ui/layout/ProfileHeader.js.map +1 -1
- package/dist/ui/layout/ScrollableRow.js +3 -2
- package/dist/ui/layout/ScrollableRow.js.map +1 -1
- package/dist/ui/layout/SectionCard.js +3 -2
- package/dist/ui/layout/SectionCard.js.map +1 -1
- package/dist/ui/metrics/BarList.js +3 -2
- package/dist/ui/metrics/BarList.js.map +1 -1
- package/dist/ui/metrics/CalendarHeatmap.js +3 -2
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
- package/dist/ui/metrics/ChartTooltip.js +3 -2
- package/dist/ui/metrics/ChartTooltip.js.map +1 -1
- package/dist/ui/metrics/ColumnChart.js +3 -2
- package/dist/ui/metrics/ColumnChart.js.map +1 -1
- package/dist/ui/metrics/LineChart.js +3 -2
- package/dist/ui/metrics/LineChart.js.map +1 -1
- package/dist/ui/metrics/MetricCard.js +3 -2
- package/dist/ui/metrics/MetricCard.js.map +1 -1
- package/dist/ui/metrics/TableToggle.js +3 -2
- package/dist/ui/metrics/TableToggle.js.map +1 -1
- package/dist/ui/metrics/chartParts.js +7 -4
- package/dist/ui/metrics/chartParts.js.map +1 -1
- package/dist/ui/navigation/BackButton.js +7 -2
- package/dist/ui/navigation/BackButton.js.map +1 -1
- package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
- package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
- package/dist/ui/navigation/FontSizeToggle.js +3 -2
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
- package/dist/ui/navigation/LanguageToggle.js +3 -2
- package/dist/ui/navigation/LanguageToggle.js.map +1 -1
- package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
- package/dist/ui/navigation/RouteTabs.js +8 -4
- package/dist/ui/navigation/RouteTabs.js.map +1 -1
- package/dist/ui/timeline/GroupedTimeline.js +3 -2
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
- package/dist/upload/AttachmentsInput.js +9 -6
- package/dist/upload/AttachmentsInput.js.map +1 -1
- package/dist/upload/FileChip.js +2 -1
- package/dist/upload/FileChip.js.map +1 -1
- package/dist/upload/FileDropzone.js +5 -4
- package/dist/upload/FileDropzone.js.map +1 -1
- package/dist/upload/FileInput.js +9 -6
- package/dist/upload/FileInput.js.map +1 -1
- package/dist/upload/FileUploadInput.js +9 -6
- package/dist/upload/FileUploadInput.js.map +1 -1
- package/dist/upload/ImageInput.js +8 -5
- package/dist/upload/ImageInput.js.map +1 -1
- package/dist/upload/TemplateDownloadButton.js +3 -2
- package/dist/upload/TemplateDownloadButton.js.map +1 -1
- package/package.json +1 -1
- package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
package/dist/forms/validation.js
CHANGED
|
@@ -1,47 +1,51 @@
|
|
|
1
1
|
import * as Yup from "yup";
|
|
2
2
|
const NAMESPACE = "validation";
|
|
3
|
-
function
|
|
4
|
-
return
|
|
3
|
+
function messageOf(name, rule, valuesOf) {
|
|
4
|
+
return (params = {}) => {
|
|
5
|
+
const values = { ...valuesOf ? valuesOf(params) : {}, ...params.label ? { label: params.label } : {} };
|
|
6
|
+
const fieldPath = params.originalPath ?? params.path;
|
|
7
|
+
return { key: `${NAMESPACE}:${name}`, values, rule, ...fieldPath ? { path: fieldPath } : {} };
|
|
8
|
+
};
|
|
5
9
|
}
|
|
6
10
|
const YUP_LOCALE = Object.freeze({
|
|
7
11
|
mixed: {
|
|
8
|
-
default:
|
|
9
|
-
required:
|
|
10
|
-
defined:
|
|
11
|
-
notNull:
|
|
12
|
-
notType:
|
|
13
|
-
oneOf: ({ values }) =>
|
|
14
|
-
notOneOf: ({ values }) =>
|
|
12
|
+
default: messageOf("default", "default"),
|
|
13
|
+
required: messageOf("required", "required"),
|
|
14
|
+
defined: messageOf("required", "defined"),
|
|
15
|
+
notNull: messageOf("required", "notNull"),
|
|
16
|
+
notType: messageOf("notType", "notType"),
|
|
17
|
+
oneOf: messageOf("oneOf", "oneOf", ({ values }) => ({ values: String(values) })),
|
|
18
|
+
notOneOf: messageOf("notOneOf", "notOneOf", ({ values }) => ({ values: String(values) }))
|
|
15
19
|
},
|
|
16
20
|
string: {
|
|
17
|
-
length: ({ length }) =>
|
|
18
|
-
min: ({ min }) =>
|
|
19
|
-
max: ({ max }) =>
|
|
20
|
-
matches:
|
|
21
|
-
email:
|
|
22
|
-
url:
|
|
23
|
-
uuid:
|
|
24
|
-
trim:
|
|
25
|
-
lowercase:
|
|
26
|
-
uppercase:
|
|
21
|
+
length: messageOf("stringLength", "length", ({ length }) => ({ count: length })),
|
|
22
|
+
min: messageOf("stringMin", "min", ({ min }) => ({ count: min })),
|
|
23
|
+
max: messageOf("stringMax", "max", ({ max }) => ({ count: max })),
|
|
24
|
+
matches: messageOf("matches", "matches"),
|
|
25
|
+
email: messageOf("email", "email"),
|
|
26
|
+
url: messageOf("url", "url"),
|
|
27
|
+
uuid: messageOf("uuid", "uuid"),
|
|
28
|
+
trim: messageOf("trim", "trim"),
|
|
29
|
+
lowercase: messageOf("lowercase", "lowercase"),
|
|
30
|
+
uppercase: messageOf("uppercase", "uppercase")
|
|
27
31
|
},
|
|
28
32
|
number: {
|
|
29
|
-
min: ({ min }) =>
|
|
30
|
-
max: ({ max }) =>
|
|
31
|
-
lessThan: ({ less }) =>
|
|
32
|
-
moreThan: ({ more }) =>
|
|
33
|
-
positive:
|
|
34
|
-
negative:
|
|
35
|
-
integer:
|
|
33
|
+
min: messageOf("numberMin", "min", ({ min }) => ({ min })),
|
|
34
|
+
max: messageOf("numberMax", "max", ({ max }) => ({ max })),
|
|
35
|
+
lessThan: messageOf("lessThan", "lessThan", ({ less }) => ({ less })),
|
|
36
|
+
moreThan: messageOf("moreThan", "moreThan", ({ more }) => ({ more })),
|
|
37
|
+
positive: messageOf("positive", "positive"),
|
|
38
|
+
negative: messageOf("negative", "negative"),
|
|
39
|
+
integer: messageOf("integer", "integer")
|
|
36
40
|
},
|
|
37
41
|
date: {
|
|
38
|
-
min: ({ min }) =>
|
|
39
|
-
max: ({ max }) =>
|
|
42
|
+
min: messageOf("dateMin", "min", ({ min }) => ({ min: String(min) })),
|
|
43
|
+
max: messageOf("dateMax", "max", ({ max }) => ({ max: String(max) }))
|
|
40
44
|
},
|
|
41
45
|
array: {
|
|
42
|
-
min: ({ min }) =>
|
|
43
|
-
max: ({ max }) =>
|
|
44
|
-
length: ({ length }) =>
|
|
46
|
+
min: messageOf("arrayMin", "min", ({ min }) => ({ count: min })),
|
|
47
|
+
max: messageOf("arrayMax", "max", ({ max }) => ({ count: max })),
|
|
48
|
+
length: messageOf("arrayLength", "length", ({ length }) => ({ count: length }))
|
|
45
49
|
}
|
|
46
50
|
});
|
|
47
51
|
function buildYupLocale() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sources":["../../src/forms/validation.js"],"sourcesContent":["// Mensajes por defecto de yup como LLAVES de i18n y no como texto.\n//\n// Por qué llaves: setLocale es global y se llama una sola vez. Con el texto en español, al cambiar a inglés los\n// errores seguirían en español hasta recargar. Con {key, values} el esquema no cambia y el texto se traduce al\n// PINTARLO (translateValidationMessage, lo usa FormTextField) en el idioma que esté activo en ese momento.\n//\n// Uso en un esquema: Yup.string().required().email() → sin textos pegados.\n// Mensaje propio de un campo: .required({key: 'auth:login.emailRequired'}) o .test('x', {key: 'modulo:llave'}, fn).\n//\n// IMPORTANTE: toda llave de aquí existe en los textos del paquete, namespace validation de locales/{es,en}.js (lo revisa\n// validation.test.js). La validación de aquí es para no gastar un viaje al servidor en lo obvio; la que protege es la\n// del backend.\n//\n// buildYupLocale() se llama UNA vez en la entrada de la aplicación, antes del primer esquema.\n//\n// Funciones puras, no renderizan: function (regla de la casa). Solo importa yup (se prueba con node --test).\nimport * as Yup from 'yup';\n\nconst NAMESPACE = 'validation';\n\n
|
|
1
|
+
{"version":3,"file":"validation.js","sources":["../../src/forms/validation.js"],"sourcesContent":["// Mensajes por defecto de yup como LLAVES de i18n y no como texto.\n//\n// Por qué llaves: setLocale es global y se llama una sola vez. Con el texto en español, al cambiar a inglés los\n// errores seguirían en español hasta recargar. Con {key, values} el esquema no cambia y el texto se traduce al\n// PINTARLO (translateValidationMessage, lo usa FormTextField) en el idioma que esté activo en ese momento.\n//\n// Uso en un esquema: Yup.string().required().email() → sin textos pegados.\n// Mensaje propio de un campo: .required({key: 'auth:login.emailRequired'}) o .test('x', {key: 'modulo:llave'}, fn).\n// O sin tocar el esquema: cada mensaje lleva su regla y su campo, y la pantalla (messages del campo) o los textos del\n// proyecto (validation:fields.<campo>.<regla>) ponen el suyo (translateValidationMessage, en validationMessages.js).\n//\n// IMPORTANTE: toda llave de aquí existe en los textos del paquete, namespace validation de locales/{es,en}.js (lo revisa\n// validation.test.js). La validación de aquí es para no gastar un viaje al servidor en lo obvio; la que protege es la\n// del backend.\n//\n// buildYupLocale() se llama UNA vez en la entrada de la aplicación, antes del primer esquema.\n//\n// Funciones puras, no renderizan: function (regla de la casa). Solo importa yup (se prueba con node --test).\nimport * as Yup from 'yup';\n\nconst NAMESPACE = 'validation';\n\n/**\n * Un mensaje de yup como llave: {key: 'validation:<nombre>', values, rule, path}.\n *\n * `rule` (la regla de yup que falló: required, min, matches…) y `path` (el campo) dejan que la pantalla o los textos del\n * proyecto pongan un mensaje propio para ese campo y esa regla sin tocar el esquema (translateValidationMessage). `label`\n * (el de .label('RFC') del esquema) va en los valores, para los textos que dicen el nombre del campo.\n *\n * @param {string} name el nombre del texto en el namespace validation\n * @param {string} rule la regla de yup\n * @param {(params: object) => object} [valuesOf] los valores del texto, sacados de lo que da yup (min, max…)\n * @returns {(params?: object) => {key: string, values: object, rule: string, path?: string}}\n */\nfunction messageOf(name, rule, valuesOf) {\n return (params = {}) => {\n const values = {...(valuesOf ? valuesOf(params) : {}), ...(params.label ? {label: params.label} : {})};\n // OJO: con .label('RFC') yup cambia params.path por el nombre visible; el campo de verdad viene en originalPath\n const fieldPath = params.originalPath ?? params.path;\n return {key: `${NAMESPACE}:${name}`, values, rule, ...(fieldPath ? {path: fieldPath} : {})};\n };\n}\n\n/** El locale de yup: cada mensaje por defecto es una llave del namespace validation, con su regla y su campo. */\nexport const YUP_LOCALE = Object.freeze({\n mixed: {\n default: messageOf('default', 'default'),\n required: messageOf('required', 'required'),\n defined: messageOf('required', 'defined'),\n notNull: messageOf('required', 'notNull'),\n notType: messageOf('notType', 'notType'),\n oneOf: messageOf('oneOf', 'oneOf', ({values}) => ({values: String(values)})),\n notOneOf: messageOf('notOneOf', 'notOneOf', ({values}) => ({values: String(values)})),\n },\n string: {\n length: messageOf('stringLength', 'length', ({length}) => ({count: length})),\n min: messageOf('stringMin', 'min', ({min}) => ({count: min})),\n max: messageOf('stringMax', 'max', ({max}) => ({count: max})),\n matches: messageOf('matches', 'matches'),\n email: messageOf('email', 'email'),\n url: messageOf('url', 'url'),\n uuid: messageOf('uuid', 'uuid'),\n trim: messageOf('trim', 'trim'),\n lowercase: messageOf('lowercase', 'lowercase'),\n uppercase: messageOf('uppercase', 'uppercase'),\n },\n number: {\n min: messageOf('numberMin', 'min', ({min}) => ({min})),\n max: messageOf('numberMax', 'max', ({max}) => ({max})),\n lessThan: messageOf('lessThan', 'lessThan', ({less}) => ({less})),\n moreThan: messageOf('moreThan', 'moreThan', ({more}) => ({more})),\n positive: messageOf('positive', 'positive'),\n negative: messageOf('negative', 'negative'),\n integer: messageOf('integer', 'integer'),\n },\n date: {\n min: messageOf('dateMin', 'min', ({min}) => ({min: String(min)})),\n max: messageOf('dateMax', 'max', ({max}) => ({max: String(max)})),\n },\n array: {\n min: messageOf('arrayMin', 'min', ({min}) => ({count: min})),\n max: messageOf('arrayMax', 'max', ({max}) => ({count: max})),\n length: messageOf('arrayLength', 'length', ({length}) => ({count: length})),\n },\n});\n\n/**\n * Instala el locale de llaves en yup. Se llama una vez en la entrada de la aplicación, antes del primer esquema.\n */\nexport function buildYupLocale() {\n Yup.setLocale(YUP_LOCALE);\n}\n\nexport {Yup};\n\n// el texto de un error en el idioma activo vive aparte (sin yup) para los campos sueltos; aquí se re-exporta\nexport {translateValidationMessage} from '@/forms/validationMessages.js';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { createLogger } from "../observability/logger.js";
|
|
2
|
+
const NAMESPACE = "validation";
|
|
3
|
+
const DEFAULT_MESSAGE_KEY = `${NAMESPACE}:default`;
|
|
4
|
+
const log = createLogger("forms");
|
|
5
|
+
const warnedShapes = /* @__PURE__ */ new Set();
|
|
6
|
+
function fieldKeyOf(path) {
|
|
7
|
+
return String(path).replace(/\[\d+\]/g, "").split(".").filter((step) => step !== "" && !/^\d+$/.test(step)).join(".");
|
|
8
|
+
}
|
|
9
|
+
function normalizedValidationMessage(error) {
|
|
10
|
+
if (typeof error === "string") {
|
|
11
|
+
return { text: error };
|
|
12
|
+
}
|
|
13
|
+
if (!error || typeof error !== "object") {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const key = typeof error.key === "string" ? error.key : typeof error.msg === "string" ? error.msg : null;
|
|
17
|
+
if (key) {
|
|
18
|
+
return { key, values: error.values ?? error.params ?? {}, rule: error.rule, path: error.path };
|
|
19
|
+
}
|
|
20
|
+
if (typeof error.message === "string") {
|
|
21
|
+
return { text: error.message };
|
|
22
|
+
}
|
|
23
|
+
if (error.message && typeof error.message === "object") {
|
|
24
|
+
const inner = normalizedValidationMessage(error.message);
|
|
25
|
+
return inner && "key" in inner && !inner.rule && error.type ? { ...inner, rule: error.type } : inner;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
function warnUnknownShape(error) {
|
|
30
|
+
const shape = Object.keys(error).sort().join(",");
|
|
31
|
+
if (warnedShapes.has(shape)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
warnedShapes.add(shape);
|
|
35
|
+
log.warn(`Un mensaje de validación con forma desconocida ({${shape}}): se enseña el mensaje general. Conéctelo con readValidationMessage de ToolkitProvider.`);
|
|
36
|
+
}
|
|
37
|
+
function translateValidationMessage(translate, error, { label, messages, readMessage, fieldName } = {}) {
|
|
38
|
+
if (error === void 0 || error === null || error === "" || error === false) {
|
|
3
39
|
return void 0;
|
|
4
40
|
}
|
|
5
|
-
|
|
6
|
-
|
|
41
|
+
const read = readMessage ? readMessage(error) : void 0;
|
|
42
|
+
const message = normalizedValidationMessage(read === void 0 || read === null ? error : read);
|
|
43
|
+
if (!message) {
|
|
44
|
+
warnUnknownShape(typeof error === "object" ? error : { value: error });
|
|
45
|
+
return translate(DEFAULT_MESSAGE_KEY);
|
|
7
46
|
}
|
|
8
|
-
if (
|
|
9
|
-
return
|
|
47
|
+
if ("text" in message) {
|
|
48
|
+
return message.text;
|
|
10
49
|
}
|
|
11
|
-
|
|
50
|
+
const values = label && message.values.label === void 0 ? { ...message.values, label } : message.values;
|
|
51
|
+
const ownMessage = message.rule ? messages?.[message.rule] : void 0;
|
|
52
|
+
if (ownMessage !== void 0 && ownMessage !== null) {
|
|
53
|
+
return translateValidationMessage(translate, ownMessage, { label });
|
|
54
|
+
}
|
|
55
|
+
const path = message.path ?? fieldName;
|
|
56
|
+
if (message.rule && path) {
|
|
57
|
+
const fieldText = translate(`${NAMESPACE}:fields.${fieldKeyOf(path)}.${message.rule}`, { ...values, defaultValue: "" });
|
|
58
|
+
if (fieldText) {
|
|
59
|
+
return fieldText;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return translate(message.key, values);
|
|
63
|
+
}
|
|
64
|
+
function ruleMessageOf(key, rule, values = {}) {
|
|
65
|
+
return { key, values, rule };
|
|
12
66
|
}
|
|
13
67
|
export {
|
|
68
|
+
fieldKeyOf,
|
|
69
|
+
normalizedValidationMessage,
|
|
70
|
+
ruleMessageOf,
|
|
14
71
|
translateValidationMessage
|
|
15
72
|
};
|
|
16
73
|
//# sourceMappingURL=validationMessages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validationMessages.js","sources":["../../src/forms/validationMessages.js"],"sourcesContent":["// El texto de un error de validación en el idioma activo. Aparte de validation.js a propósito: no importa yup, así lo usan\n// los campos sueltos de la puerta principal (inputs/) sin cargar yup en un proyecto que no valida con él.\n//\n//
|
|
1
|
+
{"version":3,"file":"validationMessages.js","sources":["../../src/forms/validationMessages.js"],"sourcesContent":["// El texto de un error de validación en el idioma activo. Aparte de validation.js a propósito: no importa yup, así lo usan\n// los campos sueltos de la puerta principal (inputs/) sin cargar yup en un proyecto que no valida con él.\n//\n// De dónde sale el texto, en este orden (el primero que exista gana):\n// 1. el de la pantalla para ese campo y esa regla: <TextInput messages={{matches: 'El RFC lleva 12 o 13 caracteres'}} />\n// 2. el de los textos del proyecto para ese campo y esa regla: validation:fields.<campo>.<regla>\n// ({es: {validation: {fields: {rfc: {matches: '…'}}}}}); el campo sin índices de lista (contacts[2].email → contacts.email)\n// 3. el del mensaje mismo: la llave que puso Calcita (buildYupLocale) o el esquema ({key: 'clientes:rfcLargo'})\n// Así el negocio pide un mensaje muy específico y se agrega un texto, sin tocar el esquema ni los mensajes de Calcita.\n//\n// Las formas de mensaje que entiende (readValidationMessage de ToolkitProvider lee cualquier otra, la de un sistema que ya\n// existe):\n// 'El correo ya existe.' un texto ya escrito (el del backend): tal cual\n// {key, values} la de Calcita (y rule y path, que pone buildYupLocale)\n// {msg, values} la de muchos sistemas con i18next (su setLocale de yup)\n// {message: 'texto'} un texto dentro de un objeto\n// {message: {…}, type} el error entero de react-hook-form: se lee su message\n// Una forma que no entiende NO se pinta como «[object Object]»: sale el mensaje general y se avisa en la consola.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createLogger} from '@/observability/logger.js';\n\nconst NAMESPACE = 'validation';\nconst DEFAULT_MESSAGE_KEY = `${NAMESPACE}:default`;\nconst log = createLogger('forms');\n// las formas de mensaje que no se entendieron y de las que ya se avisó (una vez por forma)\nconst warnedShapes = new Set();\n\n/**\n * El campo sin índices de lista, para buscar su texto propio: 'contacts[2].email' y 'contacts.2.email' son 'contacts.email'.\n *\n * @param {string} path\n * @returns {string}\n */\nexport function fieldKeyOf(path) {\n return String(path)\n .replace(/\\[\\d+\\]/g, '')\n .split('.')\n .filter((step) => step !== '' && !/^\\d+$/.test(step))\n .join('.');\n}\n\n/**\n * Un mensaje en la forma de Calcita, venga como venga.\n *\n * @param {unknown} error\n * @returns {{text: string}|{key: string, values: object, rule?: string, path?: string}|null} null: no se entendió\n */\nexport function normalizedValidationMessage(error) {\n if (typeof error === 'string') {\n return {text: error};\n }\n if (!error || typeof error !== 'object') {\n return null;\n }\n const key = typeof error.key === 'string' ? error.key : (typeof error.msg === 'string' ? error.msg : null);\n if (key) {\n return {key, values: error.values ?? error.params ?? {}, rule: error.rule, path: error.path};\n }\n if (typeof error.message === 'string') {\n return {text: error.message};\n }\n if (error.message && typeof error.message === 'object') {\n const inner = normalizedValidationMessage(error.message);\n // el error de react-hook-form trae la regla en `type`\n return inner && 'key' in inner && !inner.rule && error.type ? {...inner, rule: error.type} : inner;\n }\n return null;\n}\n\n/**\n * Avisa una vez por forma de un mensaje que no se entendió (sus llaves), en vez de pintar «[object Object]».\n *\n * @param {object} error\n * @returns {void}\n */\nfunction warnUnknownShape(error) {\n const shape = Object.keys(error).sort().join(',');\n if (warnedShapes.has(shape)) {\n return;\n }\n warnedShapes.add(shape);\n log.warn(`Un mensaje de validación con forma desconocida ({${shape}}): se enseña el mensaje general. Conéctelo con readValidationMessage de ToolkitProvider.`);\n}\n\n/**\n * Texto de un error de validación en el idioma activo.\n *\n * @param {(key: string, values?: object) => string} translate el t de useToolkitTranslation (respeta `defaultValue`, como el\n * de i18next: con él busca los textos opcionales sin avisar que faltan)\n * @param {unknown} error lo que dejó la validación en el campo\n * @param {object} [options]\n * @param {string} [options.label] el nombre del campo, para los textos que lo dicen ({{label}}: «Escriba {{label}}»)\n * @param {Record<string, string|object>} [options.messages] los textos de la pantalla para este campo, por regla\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}); ya traducidos o como {key, values}\n * @param {((error: unknown) => unknown)|null} [options.readMessage] cómo leer el mensaje de un sistema que ya existe\n * (readValidationMessage de ToolkitProvider): regresa un texto, {key, values} o undefined para la lectura de siempre\n * @param {string} [options.fieldName] el name del campo que pinta el error: para el texto propio de ese campo cuando el\n * mensaje no trae su campo (las reglas propias, los de un sistema que ya existe)\n * @returns {string|undefined}\n */\nexport function translateValidationMessage(translate, error, {label, messages, readMessage, fieldName} = {}) {\n if (error === undefined || error === null || error === '' || error === false) {\n return undefined;\n }\n const read = readMessage ? readMessage(error) : undefined;\n const message = normalizedValidationMessage(read === undefined || read === null ? error : read);\n if (!message) {\n warnUnknownShape(typeof error === 'object' ? error : {value: error});\n return translate(DEFAULT_MESSAGE_KEY);\n }\n if ('text' in message) {\n return message.text;\n }\n const values = label && message.values.label === undefined ? {...message.values, label} : message.values;\n\n // 1. el de la pantalla para esta regla\n const ownMessage = message.rule ? messages?.[message.rule] : undefined;\n if (ownMessage !== undefined && ownMessage !== null) {\n return translateValidationMessage(translate, ownMessage, {label});\n }\n // 2. el de los textos del proyecto para este campo y esta regla (opcional: sin él no se avisa que falta)\n const path = message.path ?? fieldName;\n if (message.rule && path) {\n const fieldText = translate(`${NAMESPACE}:fields.${fieldKeyOf(path)}.${message.rule}`, {...values, defaultValue: ''});\n if (fieldText) {\n return fieldText;\n }\n }\n // 3. el del mensaje\n return translate(message.key, values);\n}\n\n/**\n * El mensaje de una regla propia (.test) como lo dejan las de Calcita: su llave, sus valores y el nombre de la regla, para\n * que la pantalla (messages del campo) o los textos del proyecto (validation:fields.<campo>.<regla>) pongan el suyo sin\n * tocar el esquema. Es un objeto fijo: quien lo lea (rule.message.key) lo encuentra como siempre.\n *\n * {name: 'percent', message: ruleMessageOf('validation:percent', 'percent', {min: 0, max: 100}), test: …}\n *\n * @param {string} key la llave del texto ('validation:percent')\n * @param {string} rule el nombre de la regla\n * @param {object} [values] los valores del texto\n * @returns {{key: string, values: object, rule: string}}\n */\nexport function ruleMessageOf(key, rule, values = {}) {\n return {key, values, rule};\n}\n"],"names":[],"mappings":";AAsBA,MAAM,YAAY;AAClB,MAAM,sBAAsB,GAAG,SAAS;AACxC,MAAM,MAAM,aAAa,OAAO;AAEhC,MAAM,eAAe,oBAAI,IAAG;AAQrB,SAAS,WAAW,MAAM;AAC7B,SAAO,OAAO,IAAI,EACb,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EACT,OAAO,CAAC,SAAS,SAAS,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,EACnD,KAAK,GAAG;AACjB;AAQO,SAAS,4BAA4B,OAAO;AAC/C,MAAI,OAAO,UAAU,UAAU;AAC3B,WAAO,EAAC,MAAM,MAAK;AAAA,EACvB;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACrC,WAAO;AAAA,EACX;AACA,QAAM,MAAM,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAO,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM;AACrG,MAAI,KAAK;AACL,WAAO,EAAC,KAAK,QAAQ,MAAM,UAAU,MAAM,UAAU,CAAA,GAAI,MAAM,MAAM,MAAM,MAAM,MAAM,KAAI;AAAA,EAC/F;AACA,MAAI,OAAO,MAAM,YAAY,UAAU;AACnC,WAAO,EAAC,MAAM,MAAM,QAAO;AAAA,EAC/B;AACA,MAAI,MAAM,WAAW,OAAO,MAAM,YAAY,UAAU;AACpD,UAAM,QAAQ,4BAA4B,MAAM,OAAO;AAEvD,WAAO,SAAS,SAAS,SAAS,CAAC,MAAM,QAAQ,MAAM,OAAO,EAAC,GAAG,OAAO,MAAM,MAAM,KAAI,IAAI;AAAA,EACjG;AACA,SAAO;AACX;AAQA,SAAS,iBAAiB,OAAO;AAC7B,QAAM,QAAQ,OAAO,KAAK,KAAK,EAAE,KAAI,EAAG,KAAK,GAAG;AAChD,MAAI,aAAa,IAAI,KAAK,GAAG;AACzB;AAAA,EACJ;AACA,eAAa,IAAI,KAAK;AACtB,MAAI,KAAK,oDAAoD,KAAK,2FAA2F;AACjK;AAkBO,SAAS,2BAA2B,WAAW,OAAO,EAAC,OAAO,UAAU,aAAa,UAAS,IAAI,IAAI;AACzG,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,MAAM,UAAU,OAAO;AAC1E,WAAO;AAAA,EACX;AACA,QAAM,OAAO,cAAc,YAAY,KAAK,IAAI;AAChD,QAAM,UAAU,4BAA4B,SAAS,UAAa,SAAS,OAAO,QAAQ,IAAI;AAC9F,MAAI,CAAC,SAAS;AACV,qBAAiB,OAAO,UAAU,WAAW,QAAQ,EAAC,OAAO,MAAK,CAAC;AACnE,WAAO,UAAU,mBAAmB;AAAA,EACxC;AACA,MAAI,UAAU,SAAS;AACnB,WAAO,QAAQ;AAAA,EACnB;AACA,QAAM,SAAS,SAAS,QAAQ,OAAO,UAAU,SAAY,EAAC,GAAG,QAAQ,QAAQ,MAAK,IAAI,QAAQ;AAGlG,QAAM,aAAa,QAAQ,OAAO,WAAW,QAAQ,IAAI,IAAI;AAC7D,MAAI,eAAe,UAAa,eAAe,MAAM;AACjD,WAAO,2BAA2B,WAAW,YAAY,EAAC,MAAK,CAAC;AAAA,EACpE;AAEA,QAAM,OAAO,QAAQ,QAAQ;AAC7B,MAAI,QAAQ,QAAQ,MAAM;AACtB,UAAM,YAAY,UAAU,GAAG,SAAS,WAAW,WAAW,IAAI,CAAC,IAAI,QAAQ,IAAI,IAAI,EAAC,GAAG,QAAQ,cAAc,GAAE,CAAC;AACpH,QAAI,WAAW;AACX,aAAO;AAAA,IACX;AAAA,EACJ;AAEA,SAAO,UAAU,QAAQ,KAAK,MAAM;AACxC;AAcO,SAAS,cAAc,KAAK,MAAM,SAAS,CAAA,GAAI;AAClD,SAAO,EAAC,KAAK,QAAQ,KAAI;AAC7B;"}
|
package/dist/forms.js
CHANGED
|
@@ -13,6 +13,7 @@ import { default as default11 } from "./forms/FormProblemAlert.js";
|
|
|
13
13
|
import { default as default12 } from "./forms/FormRepeatingFields.js";
|
|
14
14
|
import { default as default13 } from "./forms/FormTransferListField.js";
|
|
15
15
|
import { listTotalAtMostRule, listTotalOf, orderedInListRule, uniqueInListRule } from "./forms/listRules.js";
|
|
16
|
+
import { percentRule, sameAsFieldRule } from "./forms/fieldRules.js";
|
|
16
17
|
import { default as default14 } from "./forms/FormSelectField.js";
|
|
17
18
|
import { default as default15 } from "./forms/FormServerProblem.js";
|
|
18
19
|
import { default as default16 } from "./forms/FormTextField.js";
|
|
@@ -68,6 +69,8 @@ export {
|
|
|
68
69
|
normalizeRecoveryCode,
|
|
69
70
|
normalizeTotpCode,
|
|
70
71
|
orderedInListRule,
|
|
72
|
+
percentRule,
|
|
73
|
+
sameAsFieldRule,
|
|
71
74
|
splitRowFieldErrors,
|
|
72
75
|
splitServerFieldErrors,
|
|
73
76
|
translateValidationMessage,
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useFormContext, useFormState } from "react-hook-form";
|
|
4
4
|
import Alert from "@mui/material/Alert";
|
|
5
|
-
import { piecePart } from "../theme/themePieces.js";
|
|
5
|
+
import { piecePart, withPieceSlots } from "../theme/themePieces.js";
|
|
6
6
|
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
7
7
|
const THEME_NAME = "CalcitaFormProblemAlert";
|
|
8
8
|
const ProblemAlert = piecePart(THEME_NAME, "Root", Alert);
|
|
9
|
-
function
|
|
9
|
+
function FormProblemAlertContent({ control, sx, ...unknownProps }) {
|
|
10
10
|
warnUnknownProps("FormProblemAlert", unknownProps);
|
|
11
11
|
const formContext = useFormContext();
|
|
12
12
|
const { errors } = useFormState({ control: control ?? formContext?.control });
|
|
@@ -16,6 +16,7 @@ function FormProblemAlert({ control, sx, ...unknownProps }) {
|
|
|
16
16
|
}
|
|
17
17
|
return /* @__PURE__ */ jsx(ProblemAlert, { severity: "error", role: "alert", sx, children: message });
|
|
18
18
|
}
|
|
19
|
+
const FormProblemAlert = withPieceSlots(FormProblemAlertContent, THEME_NAME);
|
|
19
20
|
export {
|
|
20
21
|
FormProblemAlert as default
|
|
21
22
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormProblemAlert.js","sources":["../../src/hookForm/FormProblemAlert.jsx"],"sourcesContent":["// El aviso de arriba del formulario de react-hook-form: lo que el servidor dijo que no es de un campo. applyServerProblem\n// lo deja en errors.root.server; aquí se pinta. Sin mensaje no pinta nada ni ocupa lugar.\n//\n// Se cambia desde el tema del proyecto: components.CalcitaFormProblemAlert con styleOverrides.root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Alert from '@mui/material/Alert';\nimport {piecePart} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaFormProblemAlert): el estilo del proyecto va\n// después del de MUI y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaFormProblemAlert';\nconst ProblemAlert = piecePart(THEME_NAME, 'Root', Alert);\n\n/**\n * @param {{control?: object, sx?: object}} props control: el de useForm, si la pantalla no usa FormProvider\n */\
|
|
1
|
+
{"version":3,"file":"FormProblemAlert.js","sources":["../../src/hookForm/FormProblemAlert.jsx"],"sourcesContent":["// El aviso de arriba del formulario de react-hook-form: lo que el servidor dijo que no es de un campo. applyServerProblem\n// lo deja en errors.root.server; aquí se pinta. Sin mensaje no pinta nada ni ocupa lugar.\n//\n// Se cambia desde el tema del proyecto: components.CalcitaFormProblemAlert con styleOverrides.root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Alert from '@mui/material/Alert';\nimport {piecePart, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaFormProblemAlert): el estilo del proyecto va\n// después del de MUI y el sx de la pantalla al final\nconst THEME_NAME = 'CalcitaFormProblemAlert';\nconst ProblemAlert = piecePart(THEME_NAME, 'Root', Alert);\n\n/**\n * @param {{control?: object, sx?: object}} props control: el de useForm, si la pantalla no usa FormProvider\n */\nfunction FormProblemAlertContent({control, sx, ...unknownProps}) {\n warnUnknownProps('FormProblemAlert', unknownProps);\n const formContext = useFormContext();\n const {errors} = useFormState({control: control ?? formContext?.control});\n const message = errors.root?.server?.message;\n\n // guard clause: sin aviso del servidor\n if (!message) {\n return null;\n }\n return <ProblemAlert severity=\"error\" role=\"alert\" sx={sx}>{message}</ProblemAlert>;\n}\n\nconst FormProblemAlert = withPieceSlots(FormProblemAlertContent, THEME_NAME);\nexport default FormProblemAlert;\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AAKxD,SAAS,wBAAwB,EAAC,SAAS,IAAI,GAAG,gBAAe;AAC7D,mBAAiB,oBAAoB,YAAY;AACjD,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,WAAU,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AACxE,QAAM,UAAU,OAAO,MAAM,QAAQ;AAGrC,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,6BAAQ,cAAA,EAAa,UAAS,SAAQ,MAAK,SAAQ,IAAS,UAAA,SAAQ;AACxE;AAEA,MAAM,mBAAmB,eAAe,yBAAyB,UAAU;"}
|
|
@@ -4,15 +4,29 @@ import { useState, useRef, useEffect } from "react";
|
|
|
4
4
|
import { useFormContext } from "react-hook-form";
|
|
5
5
|
import FormProblemAlert from "./FormProblemAlert.js";
|
|
6
6
|
import SubmitButton from "./SubmitButton.js";
|
|
7
|
+
import { useWizardSteps } from "../inputs/useWizardSteps.js";
|
|
7
8
|
import WizardLayout from "../inputs/WizardLayout.js";
|
|
8
9
|
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
9
|
-
function FormWizard({
|
|
10
|
+
function FormWizard({
|
|
11
|
+
steps,
|
|
12
|
+
submitLabel,
|
|
13
|
+
orientation,
|
|
14
|
+
initialStepKey,
|
|
15
|
+
stepSelection,
|
|
16
|
+
onStepChange,
|
|
17
|
+
texts,
|
|
18
|
+
...unknownProps
|
|
19
|
+
}) {
|
|
10
20
|
warnUnknownProps("FormWizard", unknownProps);
|
|
11
21
|
const { trigger, resetField, getFieldState, formState } = useFormContext();
|
|
12
22
|
const { isSubmitting, submitCount } = formState;
|
|
13
|
-
const [activeIndex, setActiveIndex] = useState(0);
|
|
14
23
|
const [skippedKeys, setSkippedKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
15
24
|
const wasSubmitting = useRef(false);
|
|
25
|
+
const isStepValid = async (index) => {
|
|
26
|
+
const stepFields = steps[index].fields ?? [];
|
|
27
|
+
return stepFields.length === 0 || trigger(stepFields, { shouldFocus: true });
|
|
28
|
+
};
|
|
29
|
+
const { activeIndex, setActiveIndex, selectStep } = useWizardSteps({ steps, initialStepKey, stepSelection, onStepChange, isStepValid });
|
|
16
30
|
const activeStep = steps[activeIndex];
|
|
17
31
|
useEffect(() => {
|
|
18
32
|
if (wasSubmitting.current && !isSubmitting) {
|
|
@@ -24,9 +38,7 @@ function FormWizard({ steps, submitLabel, texts, ...unknownProps }) {
|
|
|
24
38
|
wasSubmitting.current = isSubmitting;
|
|
25
39
|
}, [isSubmitting, submitCount]);
|
|
26
40
|
const goNext = async () => {
|
|
27
|
-
|
|
28
|
-
const isStepValid = stepFields.length === 0 || await trigger(stepFields, { shouldFocus: true });
|
|
29
|
-
if (!isStepValid) {
|
|
41
|
+
if (!await isStepValid(activeIndex)) {
|
|
30
42
|
return;
|
|
31
43
|
}
|
|
32
44
|
setSkippedKeys((currentKeys) => new Set([...currentKeys].filter((key) => key !== activeStep.key)));
|
|
@@ -46,9 +58,11 @@ function FormWizard({ steps, submitLabel, texts, ...unknownProps }) {
|
|
|
46
58
|
activeIndex,
|
|
47
59
|
skippedKeys,
|
|
48
60
|
isSubmitting,
|
|
61
|
+
orientation,
|
|
49
62
|
onBack: () => setActiveIndex((currentIndex) => currentIndex - 1),
|
|
50
63
|
onNext: goNext,
|
|
51
64
|
onSkip: skipStep,
|
|
65
|
+
onStepSelect: selectStep,
|
|
52
66
|
submitButton: /* @__PURE__ */ jsx(SubmitButton, { children: submitLabel }),
|
|
53
67
|
problemAlert: /* @__PURE__ */ jsx(FormProblemAlert, {}),
|
|
54
68
|
texts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormWizard.js","sources":["../../src/hookForm/FormWizard.jsx"],"sourcesContent":["// Formulario por pasos (wizard) con react-hook-form: el mismo del de formik (@stackcraftmx/calcita/forms), con las mismas\n// props y el mismo comportamiento:\n// - «Siguiente» revisa SOLO los campos del paso (trigger con sus nombres) y no avanza si alguno tiene error;\n// - «Omitir este paso» (solo en los opcionales) regresa sus campos a su valor de inicio (resetField): omitir es no dar ese\n// dato, no dejar lo que se escribió a medias;\n// - el último paso envía TODO el formulario (el esquema de yup completo vale para todos los pasos);\n// - si el envío falla por un campo de un paso anterior (yup o el 422 del servidor con applyServerProblem), regresa solo a\n// ese paso: un error que no se ve no se puede corregir.\n//\n// Va DENTRO de <FormProvider> y del <form> con su handleSubmit (usa useFormContext):\n// const form = useForm({resolver: yupResolver(schema), defaultValues});\n// <FormProvider {...form}>\n// <form noValidate onSubmit={form.handleSubmit(send)}>\n// <FormWizard submitLabel=\"Enviar solicitud\" steps={[\n// {key: 'datos', label: 'Sus datos', fields: ['name', 'email'], content: <>…campos…</>},\n// {key: 'aval', label: 'Aval', optional: true, fields: ['guarantor'], content: <>…</>},\n// ]} />\n// </form>\n// </FormProvider>\n//\n// Lo que se ve vive en WizardLayout (inputs/). Los textos se cambian con `texts`: {wizard: {next: 'Continuar'}}.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport {useFormContext} from 'react-hook-form';\n\nimport FormProblemAlert from '@/hookForm/FormProblemAlert.jsx';\nimport SubmitButton from '@/hookForm/SubmitButton.jsx';\nimport WizardLayout from '@/inputs/WizardLayout.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {string[]} [props.steps[].fields] los campos del paso (los que revisa «Siguiente»)\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {string} props.submitLabel ya traducido: el botón del último paso\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nexport default function FormWizard({steps, submitLabel, texts, ...unknownProps}) {\n warnUnknownProps('FormWizard', unknownProps);\n const {trigger, resetField, getFieldState, formState} = useFormContext();\n const {isSubmitting, submitCount} = formState;\n const [
|
|
1
|
+
{"version":3,"file":"FormWizard.js","sources":["../../src/hookForm/FormWizard.jsx"],"sourcesContent":["// Formulario por pasos (wizard) con react-hook-form: el mismo del de formik (@stackcraftmx/calcita/forms), con las mismas\n// props y el mismo comportamiento:\n// - «Siguiente» revisa SOLO los campos del paso (trigger con sus nombres) y no avanza si alguno tiene error;\n// - «Omitir este paso» (solo en los opcionales) regresa sus campos a su valor de inicio (resetField): omitir es no dar ese\n// dato, no dejar lo que se escribió a medias;\n// - el último paso envía TODO el formulario (el esquema de yup completo vale para todos los pasos);\n// - si el envío falla por un campo de un paso anterior (yup o el 422 del servidor con applyServerProblem), regresa solo a\n// ese paso: un error que no se ve no se puede corregir;\n// - para editar un registro (se entra a corregir un dato suelto): initialStepKey abre en el paso que diga el servidor,\n// orientation=\"vertical\" pone los campos dentro de su paso, y stepSelection deja pulsar el título de otro paso para\n// saltar directo (free) o solo si el paso abierto no tiene errores (checked). onStepChange avisa cada cambio de paso.\n//\n// Va DENTRO de <FormProvider> y del <form> con su handleSubmit (usa useFormContext):\n// const form = useForm({resolver: yupResolver(schema), defaultValues});\n// <FormProvider {...form}>\n// <form noValidate onSubmit={form.handleSubmit(send)}>\n// <FormWizard submitLabel=\"Enviar solicitud\" steps={[\n// {key: 'datos', label: 'Sus datos', fields: ['name', 'email'], content: <>…campos…</>},\n// {key: 'aval', label: 'Aval', optional: true, fields: ['guarantor'], content: <>…</>},\n// ]} />\n// </form>\n// </FormProvider>\n//\n// Lo que se ve vive en WizardLayout (inputs/). Los textos se cambian con `texts`: {wizard: {next: 'Continuar'}}.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef, useState} from 'react';\nimport {useFormContext} from 'react-hook-form';\n\nimport FormProblemAlert from '@/hookForm/FormProblemAlert.jsx';\nimport SubmitButton from '@/hookForm/SubmitButton.jsx';\nimport {useWizardSteps} from '@/inputs/useWizardSteps.js';\nimport WizardLayout from '@/inputs/WizardLayout.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {string[]} [props.steps[].fields] los campos del paso (los que revisa «Siguiente»)\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {boolean} [props.steps[].completed] lleva la palomita (cuando los títulos se pulsan, solo si la pantalla lo dice)\n * @param {string} props.submitLabel ya traducido: el botón del último paso\n * @param {'horizontal'|'vertical'} [props.orientation] uno de WIZARD_ORIENTATION; por omisión horizontal\n * @param {string} [props.initialStepKey] la llave del paso en el que se abre (la que diga el servidor); por omisión el primero\n * @param {'none'|'free'|'checked'} [props.stepSelection] uno de WIZARD_STEP_SELECTION: si el título de otro paso se pulsa y qué\n * revisa antes; por omisión none (se avanza con «Siguiente», como siempre)\n * @param {(stepKey: string, index: number) => void} [props.onStepChange] cada vez que cambia el paso abierto\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nexport default function FormWizard({\n steps, submitLabel, orientation, initialStepKey, stepSelection, onStepChange, texts, ...unknownProps\n}) {\n warnUnknownProps('FormWizard', unknownProps);\n const {trigger, resetField, getFieldState, formState} = useFormContext();\n const {isSubmitting, submitCount} = formState;\n const [skippedKeys, setSkippedKeys] = useState(() => new Set());\n const wasSubmitting = useRef(false);\n\n // revisa SOLO los campos de un paso (trigger los marca, los pinta y pone el foco en el primero con error)\n const isStepValid = async (index) => {\n const stepFields = steps[index].fields ?? [];\n return stepFields.length === 0 || trigger(stepFields, {shouldFocus: true});\n };\n const {activeIndex, setActiveIndex, selectStep} = useWizardSteps({steps, initialStepKey, stepSelection, onStepChange, isStepValid});\n const activeStep = steps[activeIndex];\n\n // al terminar un envío fallido, regresa al paso con el primer error (solo en ese momento: escribir en otro paso no\n // debe jalar a la persona de regreso). OJO: getFieldState necesita formState para leer los errores de ahora\n useEffect(() => {\n if (wasSubmitting.current && !isSubmitting) {\n const errorStepIndex = steps.findIndex((step) => (step.fields ?? []).some((field) => getFieldState(field, formState).invalid));\n if (errorStepIndex >= 0) {\n setActiveIndex(errorStepIndex);\n }\n }\n wasSubmitting.current = isSubmitting;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isSubmitting, submitCount]);\n\n const goNext = async () => {\n // el paso tiene errores: se queda ahí para que se corrijan\n if (!(await isStepValid(activeIndex))) {\n return;\n }\n setSkippedKeys((currentKeys) => new Set([...currentKeys].filter((key) => key !== activeStep.key)));\n setActiveIndex((currentIndex) => currentIndex + 1);\n };\n\n const skipStep = () => {\n for (const field of activeStep.fields ?? []) {\n resetField(field);\n }\n setSkippedKeys((currentKeys) => new Set([...currentKeys, activeStep.key]));\n setActiveIndex((currentIndex) => currentIndex + 1);\n };\n\n return (\n <WizardLayout steps={steps} activeIndex={activeIndex} skippedKeys={skippedKeys} isSubmitting={isSubmitting} orientation={orientation}\n onBack={() => setActiveIndex((currentIndex) => currentIndex - 1)} onNext={goNext} onSkip={skipStep} onStepSelect={selectStep}\n submitButton={<SubmitButton>{submitLabel}</SubmitButton>} problemAlert={<FormProblemAlert />} texts={texts} />\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAoDA,SAAwB,WAAW;AAAA,EAC/B;AAAA,EAAO;AAAA,EAAa;AAAA,EAAa;AAAA,EAAgB;AAAA,EAAe;AAAA,EAAc;AAAA,EAAO,GAAG;AAC5F,GAAG;AACC,mBAAiB,cAAc,YAAY;AAC3C,QAAM,EAAC,SAAS,YAAY,eAAe,UAAA,IAAa,eAAA;AACxD,QAAM,EAAC,cAAc,YAAA,IAAe;AACpC,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,MAAM,oBAAI,KAAK;AAC9D,QAAM,gBAAgB,OAAO,KAAK;AAGlC,QAAM,cAAc,OAAO,UAAU;AACjC,UAAM,aAAa,MAAM,KAAK,EAAE,UAAU,CAAA;AAC1C,WAAO,WAAW,WAAW,KAAK,QAAQ,YAAY,EAAC,aAAa,MAAK;AAAA,EAC7E;AACA,QAAM,EAAC,aAAa,gBAAgB,WAAA,IAAc,eAAe,EAAC,OAAO,gBAAgB,eAAe,cAAc,YAAA,CAAY;AAClI,QAAM,aAAa,MAAM,WAAW;AAIpC,YAAU,MAAM;AACZ,QAAI,cAAc,WAAW,CAAC,cAAc;AACxC,YAAM,iBAAiB,MAAM,UAAU,CAAC,UAAU,KAAK,UAAU,CAAA,GAAI,KAAK,CAAC,UAAU,cAAc,OAAO,SAAS,EAAE,OAAO,CAAC;AAC7H,UAAI,kBAAkB,GAAG;AACrB,uBAAe,cAAc;AAAA,MACjC;AAAA,IACJ;AACA,kBAAc,UAAU;AAAA,EAE5B,GAAG,CAAC,cAAc,WAAW,CAAC;AAE9B,QAAM,SAAS,YAAY;AAEvB,QAAI,CAAE,MAAM,YAAY,WAAW,GAAI;AACnC;AAAA,IACJ;AACA,mBAAe,CAAC,gBAAgB,IAAI,IAAI,CAAC,GAAG,WAAW,EAAE,OAAO,CAAC,QAAQ,QAAQ,WAAW,GAAG,CAAC,CAAC;AACjG,mBAAe,CAAC,iBAAiB,eAAe,CAAC;AAAA,EACrD;AAEA,QAAM,WAAW,MAAM;AACnB,eAAW,SAAS,WAAW,UAAU,CAAA,GAAI;AACzC,iBAAW,KAAK;AAAA,IACpB;AACA,mBAAe,CAAC,gBAAgB,oBAAI,IAAI,CAAC,GAAG,aAAa,WAAW,GAAG,CAAC,CAAC;AACzE,mBAAe,CAAC,iBAAiB,eAAe,CAAC;AAAA,EACrD;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAa;AAAA,MAAc;AAAA,MAA0B;AAAA,MAA0B;AAAA,MAA4B;AAAA,MAC9F,QAAQ,MAAM,eAAe,CAAC,iBAAiB,eAAe,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAQ,QAAQ;AAAA,MAAU,cAAc;AAAA,MAClH,cAAc,oBAAC,cAAA,EAAc,UAAA,YAAA,CAAY;AAAA,MAAiB,kCAAe,kBAAA,EAAiB;AAAA,MAAI;AAAA,IAAA;AAAA,EAAA;AAEpH;"}
|
|
@@ -3,12 +3,17 @@ import { jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useFormContext, useFormState } from "react-hook-form";
|
|
4
4
|
import Button from "@mui/material/Button";
|
|
5
5
|
import CircularProgress from "@mui/material/CircularProgress";
|
|
6
|
-
|
|
6
|
+
import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
|
|
7
|
+
const THEME_NAME = "CalcitaSubmitButton";
|
|
8
|
+
const SubmitButtonRoot = piecePart(THEME_NAME, "Root", Button);
|
|
9
|
+
function SubmitButtonContent(props) {
|
|
10
|
+
const { children, disabled, isPending, control, ...buttonProps } = usePieceProps(props, THEME_NAME);
|
|
7
11
|
const formContext = useFormContext();
|
|
8
12
|
const { isSubmitting } = useFormState({ control: control ?? formContext?.control });
|
|
9
13
|
const isBusy = Boolean(isPending ?? isSubmitting);
|
|
10
|
-
return /* @__PURE__ */ jsx(
|
|
14
|
+
return /* @__PURE__ */ jsx(SubmitButtonRoot, { type: "submit", variant: "contained", size: "large", disabled: disabled || isBusy, "aria-busy": isBusy, ...buttonProps, children: isBusy ? /* @__PURE__ */ jsx(CircularProgress, { size: 22, color: "inherit" }) : children });
|
|
11
15
|
}
|
|
16
|
+
const SubmitButton = withPieceSlots(SubmitButtonContent, THEME_NAME);
|
|
12
17
|
export {
|
|
13
18
|
SubmitButton as default
|
|
14
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubmitButton.js","sources":["../../src/hookForm/SubmitButton.jsx"],"sourcesContent":["// Botón de enviar de react-hook-form: se bloquea y muestra su indicador mientras se envía (un doble clic no manda dos\n// peticiones). Mismo look que el SubmitButton de formik.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} props.children\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.isPending] cuando el envío lo lleva una máquina de estados y no el handleSubmit\n * @param {object} [props.control] el de useForm, si la pantalla no usa FormProvider\n * @param {object} [props.sx] (y lo demás del Button de MUI: size, fullWidth, startIcon…)\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.fullWidth]\n * @param {import('react').ReactNode} [props.startIcon]\n */\
|
|
1
|
+
{"version":3,"file":"SubmitButton.js","sources":["../../src/hookForm/SubmitButton.jsx"],"sourcesContent":["// Botón de enviar de react-hook-form: se bloquea y muestra su indicador mientras se envía (un doble clic no manda dos\n// peticiones). Mismo look que el SubmitButton de formik.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSubmitButton con defaultProps, styleOverrides de\n// sus partes (root) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormContext, useFormState} from 'react-hook-form';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSubmitButton)\nconst THEME_NAME = 'CalcitaSubmitButton';\nconst SubmitButtonRoot = piecePart(THEME_NAME, 'Root', Button);\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} props.children\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.isPending] cuando el envío lo lleva una máquina de estados y no el handleSubmit\n * @param {object} [props.control] el de useForm, si la pantalla no usa FormProvider\n * @param {object} [props.sx] (y lo demás del Button de MUI: size, fullWidth, startIcon…)\n * @param {'small'|'medium'|'large'} [props.size]\n * @param {boolean} [props.fullWidth]\n * @param {import('react').ReactNode} [props.startIcon]\n */\nfunction SubmitButtonContent(props) {\n const {children, disabled, isPending, control, ...buttonProps} = usePieceProps(props, THEME_NAME);\n const formContext = useFormContext();\n const {isSubmitting} = useFormState({control: control ?? formContext?.control});\n const isBusy = Boolean(isPending ?? isSubmitting);\n\n return (\n <SubmitButtonRoot type=\"submit\" variant=\"contained\" size=\"large\" disabled={disabled || isBusy} aria-busy={isBusy} {...buttonProps}>\n {isBusy ? <CircularProgress size={22} color=\"inherit\" /> : children}\n </SubmitButtonRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst SubmitButton = withPieceSlots(SubmitButtonContent, THEME_NAME);\nexport default SubmitButton;\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,QAAQ,MAAM;AAa7D,SAAS,oBAAoB,OAAO;AAChC,QAAM,EAAC,UAAU,UAAU,WAAW,SAAS,GAAG,gBAAe,cAAc,OAAO,UAAU;AAChG,QAAM,cAAc,eAAA;AACpB,QAAM,EAAC,iBAAgB,aAAa,EAAC,SAAS,WAAW,aAAa,SAAQ;AAC9E,QAAM,SAAS,QAAQ,aAAa,YAAY;AAEhD,SACI,oBAAC,oBAAiB,MAAK,UAAS,SAAQ,aAAY,MAAK,SAAQ,UAAU,YAAY,QAAQ,aAAW,QAAS,GAAG,aACjH,UAAA,SAAS,oBAAC,kBAAA,EAAiB,MAAM,IAAI,OAAM,WAAU,IAAK,SAAA,CAC/D;AAER;AAGA,MAAM,eAAe,eAAe,qBAAqB,UAAU;"}
|
|
@@ -15,7 +15,7 @@ import Typography from "@mui/material/Typography";
|
|
|
15
15
|
import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
|
|
16
16
|
import { PHONE_MEDIA_QUERY, DESKTOP_MEDIA_QUERY } from "../appShell/shellSizes.js";
|
|
17
17
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
18
|
-
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
18
|
+
import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
|
|
19
19
|
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
20
20
|
const THEME_NAME = "CalcitaInboxLayout";
|
|
21
21
|
const InboxLabelDot = piecePart(THEME_NAME, "LabelDot", Box);
|
|
@@ -52,7 +52,7 @@ function FolderRow({ folder, isSelected, onSelect, t }) {
|
|
|
52
52
|
unreadCount > 0 && /* @__PURE__ */ jsx(InboxFolderCount, { variant: "caption", ownSx: { fontWeight: 700 }, "aria-label": t("unreadCount", { count: unreadCount }), children: unreadCount })
|
|
53
53
|
] });
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function InboxLayoutContent(props) {
|
|
56
56
|
const {
|
|
57
57
|
folders,
|
|
58
58
|
labels = [],
|
|
@@ -119,6 +119,7 @@ function InboxLayout(props) {
|
|
|
119
119
|
] })
|
|
120
120
|
] });
|
|
121
121
|
}
|
|
122
|
+
const InboxLayout = withPieceSlots(InboxLayoutContent, THEME_NAME);
|
|
122
123
|
export {
|
|
123
124
|
InboxLayout as default
|
|
124
125
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InboxLayout.js","sources":["../../src/inbox/InboxLayout.jsx"],"sourcesContent":["// El acomodo de una bandeja tipo correo: las carpetas, la lista y la lectura. En escritorio, tres columnas; en el teléfono,\n// una a la vez: las carpetas como pestañas arriba de la lista y, al abrir un mensaje, la lectura con «Regresar».\n//\n// <InboxLayout folders={folders} selectedFolderId={folderId} onSelectFolder={setFolderId} toolbar={<Buscar y Redactar />}\n// list={<MessageList … />} detail={<MessageView … />} isDetailOpen={Boolean(selectedId)} onCloseDetail={() => setSelectedId(null)} />\n//\n// Debajo de las carpetas, las etiquetas del proyecto (labels) con su punto de color, como Gmail; se eligen igual que una\n// carpeta. foldersHeader pone algo arriba de las carpetas (un botón «Redactar») y texts cambia cualquier texto.\n//\n// Escritorio o teléfono se decide con CSS (no con useMediaQuery): así el servidor pinta lo mismo que el navegador.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaInboxLayout con defaultProps y\n// styleOverrides de sus partes: labelDot, folder, folderIcon, folderCount, root, folders, foldersHeader, labelsTitle,\n// listPane, phoneTabs, phoneTabBadge, listHeader, list, detail, backButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Badge from '@mui/material/Badge';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport Paper from '@mui/material/Paper';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\nimport ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';\n\nimport {DESKTOP_MEDIA_QUERY, PHONE_MEDIA_QUERY} from '@/appShell/shellSizes.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaInboxLayout)\nconst THEME_NAME = 'CalcitaInboxLayout';\nconst InboxLabelDot = piecePart(THEME_NAME, 'LabelDot', Box);\nconst InboxFolder = piecePart(THEME_NAME, 'Folder', ListItemButton);\nconst InboxFolderIcon = piecePart(THEME_NAME, 'FolderIcon', ListItemIcon);\nconst InboxFolderCount = piecePart(THEME_NAME, 'FolderCount', Typography);\nconst InboxRoot = piecePart(THEME_NAME, 'Root', Box);\nconst InboxFolders = piecePart(THEME_NAME, 'Folders', Paper);\nconst InboxFoldersHeader = piecePart(THEME_NAME, 'FoldersHeader', Box);\nconst InboxLabelsTitle = piecePart(THEME_NAME, 'LabelsTitle', ListSubheader);\nconst InboxListPane = piecePart(THEME_NAME, 'ListPane', Paper);\nconst InboxPhoneTabs = piecePart(THEME_NAME, 'PhoneTabs', Tabs);\nconst InboxPhoneTabBadge = piecePart(THEME_NAME, 'PhoneTabBadge', Badge);\nconst InboxListHeader = piecePart(THEME_NAME, 'ListHeader', Box);\nconst InboxList = piecePart(THEME_NAME, 'List', Box);\nconst InboxDetail = piecePart(THEME_NAME, 'Detail', Paper);\nconst InboxBackButton = piecePart(THEME_NAME, 'BackButton', Button);\n\nconst FOLDERS_WIDTH_PIXELS = 220;\nconst LIST_WIDTH_PIXELS = 380;\n// la bandeja ocupa el alto de la ventana (menos la barra y el encabezado de la página): cada columna desliza por dentro\nconst DESKTOP_HEIGHT = 'calc(100dvh - 220px)';\nconst DESKTOP_MIN_HEIGHT_PIXELS = 480;\nconst LABEL_DOT_PIXELS = 10;\n\n/** Un renglón de carpeta o etiqueta: su ícono (o su punto de color), su nombre y cuántos sin leer. */\nfunction FolderRow({folder, isSelected, onSelect, t}) {\n const {id, label, Icon, color, unreadCount} = folder;\n let icon = null;\n if (Icon) {\n icon = <Icon fontSize=\"small\" />;\n } else if (color) {\n icon = <InboxLabelDot aria-hidden=\"true\" ownSx={{width: LABEL_DOT_PIXELS, height: LABEL_DOT_PIXELS, borderRadius: '50%', bgcolor: `${color}.main`, ml: 0.5}} />;\n }\n return (\n <InboxFolder selected={isSelected} onClick={() => onSelect(id)} ownSx={{borderRadius: 2}}>\n {icon && <InboxFolderIcon ownSx={{minWidth: 36}}>{icon}</InboxFolderIcon>}\n <ListItemText primary={label} />\n {unreadCount > 0 && <InboxFolderCount variant=\"caption\" ownSx={{fontWeight: 700}} aria-label={t('unreadCount', {count: unreadCount})}>{unreadCount}</InboxFolderCount>}\n </InboxFolder>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, label: string, Icon?: import('react').ElementType, unreadCount?: number}>} props.folders\n * @param {Array<{id: string, label: string, color?: string, unreadCount?: number}>} [props.labels] las etiquetas, debajo de las\n * carpetas con su punto de color (un color del tema); su id no debe repetir el de una carpeta\n * @param {string} props.selectedFolderId la carpeta o etiqueta elegida\n * @param {(folderId: string) => void} props.onSelectFolder\n * @param {import('react').ReactNode} [props.toolbar] arriba de la lista (buscar, redactar)\n * @param {import('react').ReactNode} props.list normalmente MessageList\n * @param {import('react').ReactNode} props.detail normalmente MessageView\n * @param {boolean} [props.isDetailOpen] en el teléfono, se ve la lectura en lugar de la lista\n * @param {() => void} [props.onCloseDetail] «Regresar» del teléfono\n * @param {import('react').ReactNode} [props.foldersHeader] arriba de las carpetas en escritorio (un botón «Redactar»)\n * @param {object} [props.texts] los textos que cambian, con la forma de `inbox` en los textos del paquete\n */\nexport default function InboxLayout(props) {\n // lo que el proyecto puso en su tema (components.CalcitaInboxLayout.defaultProps) y encima lo que llega aquí\n const {\n folders, labels = [], selectedFolderId, onSelectFolder, toolbar, list, detail, isDetailOpen = false, onCloseDetail, foldersHeader, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('inbox', texts);\n\n return (\n <InboxRoot ownSx={{\n display: 'grid', gap: 2,\n [DESKTOP_MEDIA_QUERY]: {\n gridTemplateColumns: `${FOLDERS_WIDTH_PIXELS}px ${LIST_WIDTH_PIXELS}px minmax(0, 1fr)`, height: DESKTOP_HEIGHT, minHeight: DESKTOP_MIN_HEIGHT_PIXELS,\n },\n }}>\n {/* las carpetas: columna en escritorio */}\n <InboxFolders variant=\"outlined\" component=\"nav\" aria-label={t('folders')} ownSx={{p: 1, overflowY: 'auto', borderRadius: 3, [PHONE_MEDIA_QUERY]: {display: 'none'}}}>\n {foldersHeader && <InboxFoldersHeader ownSx={{p: 0.5, pb: 1}}>{foldersHeader}</InboxFoldersHeader>}\n <List disablePadding>\n {folders.map((folder) => (\n <FolderRow key={folder.id} folder={folder} isSelected={folder.id === selectedFolderId} onSelect={onSelectFolder} t={t} />\n ))}\n </List>\n {labels.length > 0 && (\n <List disablePadding aria-label={t('labels')}\n subheader={<InboxLabelsTitle disableSticky ownSx={{bgcolor: 'transparent', lineHeight: 2.5, mt: 1}}>{t('labels')}</InboxLabelsTitle>}>\n {labels.map((label) => (\n <FolderRow key={label.id} folder={label} isSelected={label.id === selectedFolderId} onSelect={onSelectFolder} t={t} />\n ))}\n </List>\n )}\n </InboxFolders>\n\n {/* la lista, con las carpetas como pestañas en el teléfono */}\n <InboxListPane variant=\"outlined\" ownSx={{display: 'flex', flexDirection: 'column', minHeight: 0, borderRadius: 3, overflow: 'hidden',\n [PHONE_MEDIA_QUERY]: isDetailOpen ? {display: 'none'} : {}}}>\n <InboxPhoneTabs value={selectedFolderId} onChange={(event, folderId) => onSelectFolder(folderId)} variant=\"scrollable\" aria-label={t('folders')}\n ownSx={{px: 1, [DESKTOP_MEDIA_QUERY]: {display: 'none'}}}>\n {[...folders, ...labels].map(({id, label, unreadCount}) => (\n <Tab key={id} value={id} label={unreadCount > 0 ? <InboxPhoneTabBadge color=\"primary\" badgeContent={unreadCount} ownSx={{pr: 1.5}}>{label}</InboxPhoneTabBadge> : label} />\n ))}\n </InboxPhoneTabs>\n {toolbar && <InboxListHeader ownSx={{p: 1.5, pb: 1}}>{toolbar}</InboxListHeader>}\n <InboxList ownSx={{flex: 1, minHeight: 0, overflowY: 'auto', px: 1, pb: 1}}>{list}</InboxList>\n </InboxListPane>\n\n {/* la lectura: en el teléfono solo con un mensaje abierto, con su «Regresar» */}\n <InboxDetail variant=\"outlined\" ownSx={{p: {xs: 2, md: 3}, overflowY: 'auto', borderRadius: 3, [PHONE_MEDIA_QUERY]: isDetailOpen ? {} : {display: 'none'}}}>\n {onCloseDetail && (\n <InboxBackButton startIcon={<ArrowBackRoundedIcon />} onClick={onCloseDetail} ownSx={{mb: 1, [DESKTOP_MEDIA_QUERY]: {display: 'none'}}}>{t('back')}</InboxBackButton>\n )}\n {detail}\n </InboxDetail>\n </InboxRoot>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InboxLayout.js","sources":["../../src/inbox/InboxLayout.jsx"],"sourcesContent":["// El acomodo de una bandeja tipo correo: las carpetas, la lista y la lectura. En escritorio, tres columnas; en el teléfono,\n// una a la vez: las carpetas como pestañas arriba de la lista y, al abrir un mensaje, la lectura con «Regresar».\n//\n// <InboxLayout folders={folders} selectedFolderId={folderId} onSelectFolder={setFolderId} toolbar={<Buscar y Redactar />}\n// list={<MessageList … />} detail={<MessageView … />} isDetailOpen={Boolean(selectedId)} onCloseDetail={() => setSelectedId(null)} />\n//\n// Debajo de las carpetas, las etiquetas del proyecto (labels) con su punto de color, como Gmail; se eligen igual que una\n// carpeta. foldersHeader pone algo arriba de las carpetas (un botón «Redactar») y texts cambia cualquier texto.\n//\n// Escritorio o teléfono se decide con CSS (no con useMediaQuery): así el servidor pinta lo mismo que el navegador.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaInboxLayout con defaultProps y\n// styleOverrides de sus partes: labelDot, folder, folderIcon, folderCount, root, folders, foldersHeader, labelsTitle,\n// listPane, phoneTabs, phoneTabBadge, listHeader, list, detail, backButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Badge from '@mui/material/Badge';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport Paper from '@mui/material/Paper';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\nimport ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';\n\nimport {DESKTOP_MEDIA_QUERY, PHONE_MEDIA_QUERY} from '@/appShell/shellSizes.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaInboxLayout)\nconst THEME_NAME = 'CalcitaInboxLayout';\nconst InboxLabelDot = piecePart(THEME_NAME, 'LabelDot', Box);\nconst InboxFolder = piecePart(THEME_NAME, 'Folder', ListItemButton);\nconst InboxFolderIcon = piecePart(THEME_NAME, 'FolderIcon', ListItemIcon);\nconst InboxFolderCount = piecePart(THEME_NAME, 'FolderCount', Typography);\nconst InboxRoot = piecePart(THEME_NAME, 'Root', Box);\nconst InboxFolders = piecePart(THEME_NAME, 'Folders', Paper);\nconst InboxFoldersHeader = piecePart(THEME_NAME, 'FoldersHeader', Box);\nconst InboxLabelsTitle = piecePart(THEME_NAME, 'LabelsTitle', ListSubheader);\nconst InboxListPane = piecePart(THEME_NAME, 'ListPane', Paper);\nconst InboxPhoneTabs = piecePart(THEME_NAME, 'PhoneTabs', Tabs);\nconst InboxPhoneTabBadge = piecePart(THEME_NAME, 'PhoneTabBadge', Badge);\nconst InboxListHeader = piecePart(THEME_NAME, 'ListHeader', Box);\nconst InboxList = piecePart(THEME_NAME, 'List', Box);\nconst InboxDetail = piecePart(THEME_NAME, 'Detail', Paper);\nconst InboxBackButton = piecePart(THEME_NAME, 'BackButton', Button);\n\nconst FOLDERS_WIDTH_PIXELS = 220;\nconst LIST_WIDTH_PIXELS = 380;\n// la bandeja ocupa el alto de la ventana (menos la barra y el encabezado de la página): cada columna desliza por dentro\nconst DESKTOP_HEIGHT = 'calc(100dvh - 220px)';\nconst DESKTOP_MIN_HEIGHT_PIXELS = 480;\nconst LABEL_DOT_PIXELS = 10;\n\n/** Un renglón de carpeta o etiqueta: su ícono (o su punto de color), su nombre y cuántos sin leer. */\nfunction FolderRow({folder, isSelected, onSelect, t}) {\n const {id, label, Icon, color, unreadCount} = folder;\n let icon = null;\n if (Icon) {\n icon = <Icon fontSize=\"small\" />;\n } else if (color) {\n icon = <InboxLabelDot aria-hidden=\"true\" ownSx={{width: LABEL_DOT_PIXELS, height: LABEL_DOT_PIXELS, borderRadius: '50%', bgcolor: `${color}.main`, ml: 0.5}} />;\n }\n return (\n <InboxFolder selected={isSelected} onClick={() => onSelect(id)} ownSx={{borderRadius: 2}}>\n {icon && <InboxFolderIcon ownSx={{minWidth: 36}}>{icon}</InboxFolderIcon>}\n <ListItemText primary={label} />\n {unreadCount > 0 && <InboxFolderCount variant=\"caption\" ownSx={{fontWeight: 700}} aria-label={t('unreadCount', {count: unreadCount})}>{unreadCount}</InboxFolderCount>}\n </InboxFolder>\n );\n}\n\n/**\n * @param {object} props\n * @param {Array<{id: string, label: string, Icon?: import('react').ElementType, unreadCount?: number}>} props.folders\n * @param {Array<{id: string, label: string, color?: string, unreadCount?: number}>} [props.labels] las etiquetas, debajo de las\n * carpetas con su punto de color (un color del tema); su id no debe repetir el de una carpeta\n * @param {string} props.selectedFolderId la carpeta o etiqueta elegida\n * @param {(folderId: string) => void} props.onSelectFolder\n * @param {import('react').ReactNode} [props.toolbar] arriba de la lista (buscar, redactar)\n * @param {import('react').ReactNode} props.list normalmente MessageList\n * @param {import('react').ReactNode} props.detail normalmente MessageView\n * @param {boolean} [props.isDetailOpen] en el teléfono, se ve la lectura en lugar de la lista\n * @param {() => void} [props.onCloseDetail] «Regresar» del teléfono\n * @param {import('react').ReactNode} [props.foldersHeader] arriba de las carpetas en escritorio (un botón «Redactar»)\n * @param {object} [props.texts] los textos que cambian, con la forma de `inbox` en los textos del paquete\n */\nfunction InboxLayoutContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaInboxLayout.defaultProps) y encima lo que llega aquí\n const {\n folders, labels = [], selectedFolderId, onSelectFolder, toolbar, list, detail, isDetailOpen = false, onCloseDetail, foldersHeader, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('inbox', texts);\n\n return (\n <InboxRoot ownSx={{\n display: 'grid', gap: 2,\n [DESKTOP_MEDIA_QUERY]: {\n gridTemplateColumns: `${FOLDERS_WIDTH_PIXELS}px ${LIST_WIDTH_PIXELS}px minmax(0, 1fr)`, height: DESKTOP_HEIGHT, minHeight: DESKTOP_MIN_HEIGHT_PIXELS,\n },\n }}>\n {/* las carpetas: columna en escritorio */}\n <InboxFolders variant=\"outlined\" component=\"nav\" aria-label={t('folders')} ownSx={{p: 1, overflowY: 'auto', borderRadius: 3, [PHONE_MEDIA_QUERY]: {display: 'none'}}}>\n {foldersHeader && <InboxFoldersHeader ownSx={{p: 0.5, pb: 1}}>{foldersHeader}</InboxFoldersHeader>}\n <List disablePadding>\n {folders.map((folder) => (\n <FolderRow key={folder.id} folder={folder} isSelected={folder.id === selectedFolderId} onSelect={onSelectFolder} t={t} />\n ))}\n </List>\n {labels.length > 0 && (\n <List disablePadding aria-label={t('labels')}\n subheader={<InboxLabelsTitle disableSticky ownSx={{bgcolor: 'transparent', lineHeight: 2.5, mt: 1}}>{t('labels')}</InboxLabelsTitle>}>\n {labels.map((label) => (\n <FolderRow key={label.id} folder={label} isSelected={label.id === selectedFolderId} onSelect={onSelectFolder} t={t} />\n ))}\n </List>\n )}\n </InboxFolders>\n\n {/* la lista, con las carpetas como pestañas en el teléfono */}\n <InboxListPane variant=\"outlined\" ownSx={{display: 'flex', flexDirection: 'column', minHeight: 0, borderRadius: 3, overflow: 'hidden',\n [PHONE_MEDIA_QUERY]: isDetailOpen ? {display: 'none'} : {}}}>\n <InboxPhoneTabs value={selectedFolderId} onChange={(event, folderId) => onSelectFolder(folderId)} variant=\"scrollable\" aria-label={t('folders')}\n ownSx={{px: 1, [DESKTOP_MEDIA_QUERY]: {display: 'none'}}}>\n {[...folders, ...labels].map(({id, label, unreadCount}) => (\n <Tab key={id} value={id} label={unreadCount > 0 ? <InboxPhoneTabBadge color=\"primary\" badgeContent={unreadCount} ownSx={{pr: 1.5}}>{label}</InboxPhoneTabBadge> : label} />\n ))}\n </InboxPhoneTabs>\n {toolbar && <InboxListHeader ownSx={{p: 1.5, pb: 1}}>{toolbar}</InboxListHeader>}\n <InboxList ownSx={{flex: 1, minHeight: 0, overflowY: 'auto', px: 1, pb: 1}}>{list}</InboxList>\n </InboxListPane>\n\n {/* la lectura: en el teléfono solo con un mensaje abierto, con su «Regresar» */}\n <InboxDetail variant=\"outlined\" ownSx={{p: {xs: 2, md: 3}, overflowY: 'auto', borderRadius: 3, [PHONE_MEDIA_QUERY]: isDetailOpen ? {} : {display: 'none'}}}>\n {onCloseDetail && (\n <InboxBackButton startIcon={<ArrowBackRoundedIcon />} onClick={onCloseDetail} ownSx={{mb: 1, [DESKTOP_MEDIA_QUERY]: {display: 'none'}}}>{t('back')}</InboxBackButton>\n )}\n {detail}\n </InboxDetail>\n </InboxRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst InboxLayout = withPieceSlots(InboxLayoutContent, THEME_NAME);\nexport default InboxLayout;\n"],"names":[],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ import { useFormatters } from "../toolkit/useFormatters.js";
|
|
|
21
21
|
import { tagOf } from "../ui/labels/tagOf.js";
|
|
22
22
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
23
23
|
import ActionsMenu from "../ui/actions/ActionsMenu.js";
|
|
24
|
-
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
24
|
+
import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
|
|
25
25
|
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
26
26
|
const THEME_NAME = "CalcitaMessageList";
|
|
27
27
|
const MessagesEmpty = piecePart(THEME_NAME, "Empty", Typography);
|
|
@@ -44,7 +44,7 @@ const MessagesSubject = piecePart(THEME_NAME, "Subject", Typography);
|
|
|
44
44
|
const MessagesLabels = piecePart(THEME_NAME, "Labels", Stack);
|
|
45
45
|
const UNREAD_DOT_PIXELS = 8;
|
|
46
46
|
const AVATAR_PIXELS = 40;
|
|
47
|
-
function
|
|
47
|
+
function MessageListContent(props) {
|
|
48
48
|
const {
|
|
49
49
|
messages,
|
|
50
50
|
selectedId = null,
|
|
@@ -132,6 +132,7 @@ function MessageList(props) {
|
|
|
132
132
|
) }, message.id);
|
|
133
133
|
}) });
|
|
134
134
|
}
|
|
135
|
+
const MessageList = withPieceSlots(MessageListContent, THEME_NAME);
|
|
135
136
|
export {
|
|
136
137
|
MessageList as default
|
|
137
138
|
};
|