@stackcraftmx/calcita 0.23.0 → 0.26.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 +127 -22
- package/cli/projectFiles.js +5 -3
- package/cli/templates/project/README.md.tpl +28 -0
- package/cli/templates/project/public/manifest.webmanifest.tpl +6 -6
- package/cli/templates/project/src/app/AppProviders.jsx.tpl +9 -4
- package/cli/templates/project/src/app/appRouter.jsx.tpl +4 -2
- package/cli/templates/project/src/app/appSettings.js.tpl +14 -0
- package/cli/templates/project/src/core/AppLogo.jsx.tpl +3 -1
- package/cli/templates/project/src/core/index.js.tpl +1 -0
- package/cli/templates/project/src/core/publicPaths.js.tpl +24 -0
- package/cli/templates/project/vite.config.js.tpl +27 -1
- package/dist/DataTable/AuditTrailTable.js +5 -3
- package/dist/DataTable/AuditTrailTable.js.map +1 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +2 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
- package/dist/DataTable/EmptyState.js +2 -2
- package/dist/DataTable/EmptyState.js.map +1 -1
- package/dist/DataTable/FilterChips.js +2 -2
- package/dist/DataTable/FilterChips.js.map +1 -1
- package/dist/DataTable/GoToPage.js +4 -3
- package/dist/DataTable/GoToPage.js.map +1 -1
- package/dist/DataTable/ServerTable.js +153 -83
- package/dist/DataTable/ServerTable.js.map +1 -1
- package/dist/DataTable/rowSelection.js +61 -0
- package/dist/DataTable/rowSelection.js.map +1 -0
- package/dist/access/PermissionMatrix.js +3 -2
- package/dist/access/PermissionMatrix.js.map +1 -1
- package/dist/account/AccountSecuritySection.js +2 -2
- package/dist/account/AccountSecuritySection.js.map +1 -1
- package/dist/account/ForgotPasswordScreen.js +5 -4
- package/dist/account/ForgotPasswordScreen.js.map +1 -1
- package/dist/account/ProfileScreen.js +39 -13
- package/dist/account/ProfileScreen.js.map +1 -1
- package/dist/account/ResetPasswordScreen.js +3 -2
- package/dist/account/ResetPasswordScreen.js.map +1 -1
- package/dist/account/SignInScreen.js +7 -6
- package/dist/account/SignInScreen.js.map +1 -1
- package/dist/account/accountConnector.js.map +1 -1
- package/dist/account/restAccountConnector.js +2 -1
- package/dist/account/restAccountConnector.js.map +1 -1
- package/dist/adapters/reactRouterRoutes.js +7 -6
- package/dist/adapters/reactRouterRoutes.js.map +1 -1
- package/dist/api/createApiClient.js +40 -5
- package/dist/api/createApiClient.js.map +1 -1
- package/dist/appShell/AccountMenu.js +15 -23
- package/dist/appShell/AccountMenu.js.map +1 -1
- package/dist/appShell/AppLayout.js +42 -15
- package/dist/appShell/AppLayout.js.map +1 -1
- package/dist/appShell/AppearanceSettings.js +29 -6
- package/dist/appShell/AppearanceSettings.js.map +1 -1
- package/dist/appShell/AuthLayout.js +2 -0
- package/dist/appShell/AuthLayout.js.map +1 -1
- package/dist/appShell/BarActionButton.js +3 -3
- package/dist/appShell/BarActionButton.js.map +1 -1
- package/dist/appShell/BarActions.js +19 -8
- package/dist/appShell/BarActions.js.map +1 -1
- package/dist/appShell/BarCapsule.js +19 -4
- package/dist/appShell/BarCapsule.js.map +1 -1
- package/dist/appShell/BarSearch.js +92 -0
- package/dist/appShell/BarSearch.js.map +1 -0
- package/dist/appShell/HeaderTools.js +4 -2
- package/dist/appShell/HeaderTools.js.map +1 -1
- package/dist/appShell/MenuLinks.js +36 -0
- package/dist/appShell/MenuLinks.js.map +1 -0
- package/dist/appShell/MobileTabBar.js +6 -4
- package/dist/appShell/MobileTabBar.js.map +1 -1
- package/dist/appShell/SettingsMenu.js +10 -5
- package/dist/appShell/SettingsMenu.js.map +1 -1
- package/dist/appShell/SideMenu.js +5 -3
- package/dist/appShell/SideMenu.js.map +1 -1
- package/dist/appShell/SideMenuEntry.js +3 -3
- package/dist/appShell/SideMenuEntry.js.map +1 -1
- package/dist/appShell/SubmenuActionsMenu.js +3 -4
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
- package/dist/appShell/TopMenu.js +5 -6
- package/dist/appShell/TopMenu.js.map +1 -1
- package/dist/appShell/Wordmark.js +11 -0
- package/dist/appShell/Wordmark.js.map +1 -0
- package/dist/appShell/menuItemText.js +4 -0
- package/dist/appShell/menuItemText.js.map +1 -1
- package/dist/appShell/shellSizes.js +2 -0
- package/dist/appShell/shellSizes.js.map +1 -1
- package/dist/auth/PasswordChecklist.js +2 -2
- package/dist/auth/PasswordChecklist.js.map +1 -1
- package/dist/calendar/EventCalendar.js +16 -5
- package/dist/calendar/EventCalendar.js.map +1 -1
- package/dist/calendar/EventDetails.js +74 -0
- package/dist/calendar/EventDetails.js.map +1 -0
- package/dist/calendar/calendarEvents.js +31 -0
- package/dist/calendar/calendarEvents.js.map +1 -0
- package/dist/calendar.js +8 -1
- package/dist/calendar.js.map +1 -1
- package/dist/charts.js +10 -1
- package/dist/charts.js.map +1 -1
- package/dist/datePickers/DateInput.js +3 -2
- package/dist/datePickers/DateInput.js.map +1 -1
- package/dist/downloads/DownloadManager.js +14 -20
- package/dist/downloads/DownloadManager.js.map +1 -1
- package/dist/downloads/downloadQueue.js +4 -2
- package/dist/downloads/downloadQueue.js.map +1 -1
- package/dist/downloads/downloadsMachine.js +4 -1
- package/dist/downloads/downloadsMachine.js.map +1 -1
- package/dist/downloads/fileTypes.js +22 -0
- package/dist/downloads/fileTypes.js.map +1 -0
- package/dist/feedback/ConfirmDialog.js +3 -2
- package/dist/feedback/ConfirmDialog.js.map +1 -1
- package/dist/feedback/ModalWaiting.js +2 -2
- package/dist/feedback/ModalWaiting.js.map +1 -1
- package/dist/feedback/NewBuildNotice.js +2 -2
- package/dist/feedback/NewBuildNotice.js.map +1 -1
- package/dist/filepond/FileDropzone.js +5 -3
- package/dist/filepond/FileDropzone.js.map +1 -1
- package/dist/formatting.js +171 -143
- package/dist/formatting.js.map +1 -1
- package/dist/forms/FormWizard.js +18 -45
- package/dist/forms/FormWizard.js.map +1 -1
- package/dist/forms/auth/ChangePasswordForm.js +5 -4
- package/dist/forms/auth/ChangePasswordForm.js.map +1 -1
- package/dist/forms/auth/ForgotPasswordForm.js +2 -2
- package/dist/forms/auth/ForgotPasswordForm.js.map +1 -1
- package/dist/forms/auth/SignInForm.js +2 -2
- package/dist/forms/auth/SignInForm.js.map +1 -1
- package/dist/forms/security/SecondStepForm.js +2 -2
- package/dist/forms/security/SecondStepForm.js.map +1 -1
- package/dist/forms/security/TwoStepVerificationCard.js +8 -6
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
- package/dist/hookForm/FormWizard.js +59 -0
- package/dist/hookForm/FormWizard.js.map +1 -0
- package/dist/inbox/InboxLayout.js +44 -8
- package/dist/inbox/InboxLayout.js.map +1 -1
- package/dist/inbox/MessageList.js +71 -21
- package/dist/inbox/MessageList.js.map +1 -1
- package/dist/inbox/MessageView.js +80 -29
- package/dist/inbox/MessageView.js.map +1 -1
- package/dist/inbox/inboxDates.js +4 -3
- package/dist/inbox/inboxDates.js.map +1 -1
- package/dist/index.js +163 -136
- package/dist/index.js.map +1 -1
- package/dist/inputs/CatalogInput.js +8 -4
- package/dist/inputs/CatalogInput.js.map +1 -1
- package/dist/inputs/ColorInput.js +3 -2
- package/dist/inputs/ColorInput.js.map +1 -1
- package/dist/inputs/FormSection.js +3 -3
- package/dist/inputs/FormSection.js.map +1 -1
- package/dist/inputs/NumberInput.js +3 -2
- package/dist/inputs/NumberInput.js.map +1 -1
- package/dist/inputs/SelectInput.js +29 -11
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/TextInput.js +6 -2
- package/dist/inputs/TextInput.js.map +1 -1
- package/dist/inputs/WizardLayout.js +54 -0
- package/dist/inputs/WizardLayout.js.map +1 -0
- package/dist/kanban/KanbanBoard.js +239 -14
- package/dist/kanban/KanbanBoard.js.map +1 -1
- package/dist/kanban/kanbanCards.js +19 -0
- package/dist/kanban/kanbanCards.js.map +1 -0
- package/dist/kanban.js +7 -1
- package/dist/kanban.js.map +1 -1
- package/dist/locales/en.js +74 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +74 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/maps/MapView.js +28 -8
- package/dist/maps/MapView.js.map +1 -1
- package/dist/navigation/appMenu.js +13 -1
- package/dist/navigation/appMenu.js.map +1 -1
- package/dist/observability/logger.js +18 -0
- package/dist/observability/logger.js.map +1 -1
- package/dist/observability/usePublishedBuildWatch.js +4 -3
- package/dist/observability/usePublishedBuildWatch.js.map +1 -1
- package/dist/pwa/InstallAppSetting.js +6 -5
- package/dist/pwa/InstallAppSetting.js.map +1 -1
- package/dist/pwa/InstallInstructionsDialog.js +2 -2
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
- package/dist/pwa/InstallPromptBanner.js +15 -9
- package/dist/pwa/InstallPromptBanner.js.map +1 -1
- package/dist/pwa/useInstallPrompt.js +2 -1
- package/dist/pwa/useInstallPrompt.js.map +1 -1
- package/dist/react-hook-form.js +6 -4
- package/dist/react-hook-form.js.map +1 -1
- package/dist/security/ActivityLog.js +4 -3
- package/dist/security/ActivityLog.js.map +1 -1
- package/dist/security/RecoveryCodesDialog.js +4 -3
- package/dist/security/RecoveryCodesDialog.js.map +1 -1
- package/dist/security/SessionsCard.js +8 -6
- package/dist/security/SessionsCard.js.map +1 -1
- package/dist/table.js +2 -0
- package/dist/table.js.map +1 -1
- package/dist/theme/components/MuiAppBar.js +6 -5
- package/dist/theme/components/MuiAppBar.js.map +1 -1
- package/dist/theme/components/MuiDialog.js +13 -0
- package/dist/theme/components/MuiDialog.js.map +1 -0
- package/dist/theme/components/glassComponents.js +32 -31
- package/dist/theme/components/glassComponents.js.map +1 -1
- package/dist/theme/components/minimalComponents.js +8 -4
- package/dist/theme/components/minimalComponents.js.map +1 -1
- package/dist/theme/createToolkitTheme.js.map +1 -1
- package/dist/theme/glassSurface.js +36 -38
- package/dist/theme/glassSurface.js.map +1 -1
- package/dist/theme/lightDarkStyles.js +48 -0
- package/dist/theme/lightDarkStyles.js.map +1 -0
- package/dist/theme/toolkitComponents.js +2 -0
- package/dist/theme/toolkitComponents.js.map +1 -1
- package/dist/toolkit/ComponentTexts.js +13 -0
- package/dist/toolkit/ComponentTexts.js.map +1 -0
- package/dist/toolkit/ToolkitProvider.js +36 -28
- package/dist/toolkit/ToolkitProvider.js.map +1 -1
- package/dist/toolkit/browserNavigation.js +19 -20
- package/dist/toolkit/browserNavigation.js.map +1 -1
- package/dist/toolkit/componentTextsContext.js +15 -0
- package/dist/toolkit/componentTextsContext.js.map +1 -0
- package/dist/toolkit/hashNavigation.js +40 -0
- package/dist/toolkit/hashNavigation.js.map +1 -0
- package/dist/toolkit/navigationPaths.js +49 -0
- package/dist/toolkit/navigationPaths.js.map +1 -0
- package/dist/toolkit/toolkitSettings.js +24 -4
- package/dist/toolkit/toolkitSettings.js.map +1 -1
- package/dist/toolkit/useFormatters.js +12 -0
- package/dist/toolkit/useFormatters.js.map +1 -0
- package/dist/toolkit/useToolkitTranslation.js +11 -7
- package/dist/toolkit/useToolkitTranslation.js.map +1 -1
- package/dist/types/DataTable/AuditTrailTable.d.ts +3 -1
- package/dist/types/DataTable/EmptyState.d.ts +7 -2
- package/dist/types/DataTable/FilterChips.d.ts +3 -1
- package/dist/types/DataTable/GoToPage.d.ts +7 -2
- package/dist/types/DataTable/SelectionBar.d.ts +32 -0
- package/dist/types/DataTable/ServerTable.d.ts +64 -3
- package/dist/types/DataTable/index.d.ts +1 -1
- package/dist/types/DataTable/rowSelection.d.ts +113 -0
- package/dist/types/access/PermissionMatrix.d.ts +3 -1
- package/dist/types/account/AccountSecuritySection.d.ts +3 -1
- package/dist/types/account/ForgotPasswordScreen.d.ts +3 -1
- package/dist/types/account/ProfileScreen.d.ts +31 -1
- package/dist/types/account/ResetPasswordScreen.d.ts +3 -1
- package/dist/types/account/SignInScreen.d.ts +3 -1
- package/dist/types/account/accountConnector.d.ts +7 -2
- package/dist/types/adapters/reactRouterRoutes.d.ts +14 -2
- package/dist/types/api/createApiClient.d.ts +46 -1
- package/dist/types/appShell/AppLayout.d.ts +15 -1
- package/dist/types/appShell/AppearanceSettings.d.ts +8 -1
- package/dist/types/appShell/BarActionButton.d.ts +2 -2
- package/dist/types/appShell/BarActions.d.ts +6 -1
- package/dist/types/appShell/BarCapsule.d.ts +8 -0
- package/dist/types/appShell/BarSearch.d.ts +24 -0
- package/dist/types/appShell/MenuLinks.d.ts +17 -0
- package/dist/types/appShell/MobileTabBar.d.ts +4 -1
- package/dist/types/appShell/SettingsMenu.d.ts +3 -1
- package/dist/types/appShell/SideMenu.d.ts +3 -1
- package/dist/types/appShell/Wordmark.d.ts +6 -0
- package/dist/types/appShell/menuItemText.d.ts +16 -0
- package/dist/types/appShell/shellSizes.d.ts +1 -0
- package/dist/types/auth/PasswordChecklist.d.ts +3 -1
- package/dist/types/calendar/EventCalendar.d.ts +18 -1
- package/dist/types/calendar/EventDetails.d.ts +36 -0
- package/dist/types/calendar/calendarEvents.d.ts +27 -0
- package/dist/types/calendar.d.ts +2 -0
- package/dist/types/charts.d.ts +4 -0
- package/dist/types/datePickers/DateInput.d.ts +3 -1
- package/dist/types/downloads/DownloadManager.d.ts +7 -1
- package/dist/types/downloads/downloadQueue.d.ts +8 -3
- package/dist/types/downloads/fileTypes.d.ts +39 -0
- package/dist/types/downloads/index.d.ts +1 -0
- package/dist/types/feedback/ConfirmDialog.d.ts +3 -1
- package/dist/types/feedback/ModalWaiting.d.ts +7 -2
- package/dist/types/feedback/NewBuildNotice.d.ts +3 -1
- package/dist/types/filepond/FileDropzone.d.ts +3 -1
- package/dist/types/formatting.d.ts +45 -90
- package/dist/types/forms/FormWizard.d.ts +3 -1
- package/dist/types/forms/auth/ChangePasswordForm.d.ts +3 -1
- package/dist/types/forms/auth/ForgotPasswordForm.d.ts +3 -1
- package/dist/types/forms/auth/SignInForm.d.ts +3 -1
- package/dist/types/forms/security/SecondStepForm.d.ts +3 -1
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +3 -1
- package/dist/types/hookForm/FormWizard.d.ts +22 -0
- package/dist/types/inbox/InboxLayout.d.ts +14 -2
- package/dist/types/inbox/MessageList.d.ts +30 -5
- package/dist/types/inbox/MessageView.d.ts +35 -3
- package/dist/types/inbox/inboxDates.d.ts +6 -1
- package/dist/types/index.d.ts +15 -8
- package/dist/types/inputs/CatalogInput.d.ts +9 -5
- package/dist/types/inputs/ColorInput.d.ts +3 -1
- package/dist/types/inputs/FormSection.d.ts +2 -2
- package/dist/types/inputs/NumberInput.d.ts +3 -1
- package/dist/types/inputs/SelectInput.d.ts +9 -5
- package/dist/types/inputs/TextInput.d.ts +3 -1
- package/dist/types/inputs/WizardLayout.d.ts +34 -0
- package/dist/types/kanban/KanbanBoard.d.ts +61 -6
- package/dist/types/kanban/kanbanCards.d.ts +22 -0
- package/dist/types/kanban.d.ts +1 -0
- package/dist/types/locales/en.d.ts +77 -0
- package/dist/types/locales/es.d.ts +77 -0
- package/dist/types/maps/MapView.d.ts +12 -3
- package/dist/types/navigation/appMenu.d.ts +8 -0
- package/dist/types/observability/logger.d.ts +13 -0
- package/dist/types/observability/usePublishedBuildWatch.d.ts +3 -1
- package/dist/types/pwa/InstallAppSetting.d.ts +7 -1
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +3 -1
- package/dist/types/pwa/InstallPromptBanner.d.ts +10 -1
- package/dist/types/pwa/useInstallPrompt.d.ts +3 -2
- package/dist/types/react-hook-form.d.ts +1 -0
- package/dist/types/security/ActivityLog.d.ts +3 -1
- package/dist/types/security/RecoveryCodesDialog.d.ts +6 -1
- package/dist/types/security/SessionsCard.d.ts +3 -1
- package/dist/types/table.d.ts +3 -1
- package/dist/types/theme/components/MuiAppBar.d.ts +3 -1
- package/dist/types/theme/components/MuiDialog.d.ts +9 -0
- package/dist/types/theme/components/glassComponents.d.ts +5 -0
- package/dist/types/theme/lightDarkStyles.d.ts +8 -0
- package/dist/types/toolkit/ComponentTexts.d.ts +11 -0
- package/dist/types/toolkit/ToolkitProvider.d.ts +18 -2
- package/dist/types/toolkit/browserNavigation.d.ts +23 -28
- package/dist/types/toolkit/componentTextsContext.d.ts +20 -0
- package/dist/types/toolkit/hashNavigation.d.ts +12 -0
- package/dist/types/toolkit/navigationPaths.d.ts +43 -0
- package/dist/types/toolkit/toolkitSettings.d.ts +49 -4
- package/dist/types/toolkit/useFormatters.d.ts +6 -0
- package/dist/types/toolkit/useToolkitTranslation.d.ts +2 -1
- package/dist/types/ui/actions/ActionsMenu.d.ts +20 -0
- package/dist/types/ui/actions/CopyButton.d.ts +3 -1
- package/dist/types/ui/actions/DownloadMenu.d.ts +8 -3
- package/dist/types/ui/actions/SecretField.d.ts +5 -1
- package/dist/types/ui/actions/SelectionActions.d.ts +39 -0
- package/dist/types/ui/filters/DateRangeFilter.d.ts +3 -1
- package/dist/types/ui/filters/QuickFilters.d.ts +3 -1
- package/dist/types/ui/index.d.ts +1 -1
- package/dist/types/ui/labels/tagOf.d.ts +13 -0
- package/dist/types/ui/layout/CollapsibleSection.d.ts +4 -1
- package/dist/types/ui/layout/ContentDialog.d.ts +3 -1
- package/dist/types/ui/layout/ErrorPage.d.ts +14 -1
- package/dist/types/ui/layout/FullPageLoader.d.ts +7 -1
- package/dist/types/ui/layout/PageHeading.d.ts +3 -1
- package/dist/types/ui/metrics/BarList.d.ts +7 -1
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +7 -1
- package/dist/types/ui/metrics/ChartTooltip.d.ts +9 -3
- package/dist/types/ui/metrics/ColumnChart.d.ts +23 -11
- package/dist/types/ui/metrics/LineChart.d.ts +41 -0
- package/dist/types/ui/metrics/MetricCard.d.ts +9 -1
- package/dist/types/ui/metrics/TableToggle.d.ts +9 -2
- package/dist/types/ui/metrics/chartParts.d.ts +112 -0
- package/dist/types/ui/navigation/BackButton.d.ts +3 -1
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +8 -2
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +7 -2
- package/dist/types/ui/navigation/LanguageToggle.d.ts +8 -3
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +5 -2
- package/dist/types/ui/timeline/GroupedTimeline.d.ts +4 -1
- package/dist/types/upload/FileDropzone.d.ts +3 -1
- package/dist/ui/actions/ActionsMenu.js +51 -0
- package/dist/ui/actions/ActionsMenu.js.map +1 -0
- package/dist/ui/actions/CopyButton.js +2 -2
- package/dist/ui/actions/CopyButton.js.map +1 -1
- package/dist/ui/actions/DownloadMenu.js +11 -12
- package/dist/ui/actions/DownloadMenu.js.map +1 -1
- package/dist/ui/actions/SecretField.js +8 -4
- package/dist/ui/actions/SecretField.js.map +1 -1
- package/dist/ui/actions/SelectionActions.js +142 -0
- package/dist/ui/actions/SelectionActions.js.map +1 -0
- package/dist/ui/filters/DateRangeFilter.js +4 -3
- package/dist/ui/filters/DateRangeFilter.js.map +1 -1
- package/dist/ui/filters/QuickFilters.js +2 -2
- package/dist/ui/filters/QuickFilters.js.map +1 -1
- package/dist/ui/labels/tagOf.js +7 -0
- package/dist/ui/labels/tagOf.js.map +1 -0
- package/dist/ui/layout/CollapsibleSection.js +6 -2
- package/dist/ui/layout/CollapsibleSection.js.map +1 -1
- package/dist/ui/layout/ContentDialog.js +2 -2
- package/dist/ui/layout/ContentDialog.js.map +1 -1
- package/dist/ui/layout/ErrorPage.js +21 -7
- package/dist/ui/layout/ErrorPage.js.map +1 -1
- package/dist/ui/layout/FullPageLoader.js +2 -2
- package/dist/ui/layout/FullPageLoader.js.map +1 -1
- package/dist/ui/layout/PageHeading.js +2 -2
- package/dist/ui/layout/PageHeading.js.map +1 -1
- package/dist/ui/metrics/BarList.js +18 -13
- package/dist/ui/metrics/BarList.js.map +1 -1
- package/dist/ui/metrics/CalendarHeatmap.js +11 -6
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
- package/dist/ui/metrics/ChartTooltip.js +1 -1
- package/dist/ui/metrics/ChartTooltip.js.map +1 -1
- package/dist/ui/metrics/ColumnChart.js +59 -63
- package/dist/ui/metrics/ColumnChart.js.map +1 -1
- package/dist/ui/metrics/LineChart.js +117 -0
- package/dist/ui/metrics/LineChart.js.map +1 -0
- package/dist/ui/metrics/MetricCard.js +41 -8
- package/dist/ui/metrics/MetricCard.js.map +1 -1
- package/dist/ui/metrics/TableToggle.js +4 -2
- package/dist/ui/metrics/TableToggle.js.map +1 -1
- package/dist/ui/metrics/chartParts.js +93 -0
- package/dist/ui/metrics/chartParts.js.map +1 -0
- package/dist/ui/navigation/BackButton.js +2 -2
- package/dist/ui/navigation/BackButton.js.map +1 -1
- package/dist/ui/navigation/ColorSchemeToggle.js +6 -3
- 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 +40 -19
- package/dist/ui/navigation/LanguageToggle.js.map +1 -1
- package/dist/ui/navigation/PageBreadcrumbs.js +2 -2
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
- package/dist/ui/timeline/GroupedTimeline.js +10 -8
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
- package/dist/upload/FileDropzone.js +5 -3
- package/dist/upload/FileDropzone.js.map +1 -1
- package/package.json +16 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupedTimeline.js","sources":["../../../src/ui/timeline/GroupedTimeline.jsx"],"sourcesContent":["// Línea de tiempo por grupos (Timeline de @mui/lab al estilo del ejemplo «Customization» de MUI): cada grupo con su\n// título y una insignia opcional, y cada evento con su ícono dentro del punto, su título, su hora y un detalle libre.\n//\n// Uso típico: el historial de un registro agrupado por etapa o por intento (detalle de un pedido: un grupo por intento de entrega,\n// el vigente resaltado). El énfasis de cada grupo (TIMELINE_EMPHASIS) decide cómo se pintan sus puntos (timelineDot.js).\n//\n// En pantalla ancha los eventos alternan de lado y la hora va del otro lado del punto; en celular todo va de un lado, con\n// la hora abajo del título, para que quepa.\n//\n// Un grupo plegable (isCollapsible) enseña solo su título y su resumen hasta que se abre: sirve para que lo viejo no\n// obligue a bajar (los intentos anteriores van plegados).\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: títulos, horas y detalles llegan ya traducidos y\n// formateados, y el ícono y el tono de cada evento los decide quien la usa (con sus diccionarios).\nimport {useState} from 'react';\nimport Timeline from '@mui/lab/Timeline';\nimport TimelineConnector from '@mui/lab/TimelineConnector';\nimport TimelineContent from '@mui/lab/TimelineContent';\nimport TimelineDot from '@mui/lab/TimelineDot';\nimport TimelineItem, {timelineItemClasses} from '@mui/lab/TimelineItem';\nimport TimelineOppositeContent from '@mui/lab/TimelineOppositeContent';\nimport TimelineSeparator from '@mui/lab/TimelineSeparator';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Chip from '@mui/material/Chip';\nimport Collapse from '@mui/material/Collapse';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport useMediaQuery from '@mui/material/useMediaQuery';\nimport {useTheme} from '@mui/material/styles';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\n\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {TIMELINE_EMPHASIS, timelineDotOf} from '@/ui/timeline/timelineDot.js';\n\n// el fondo del grupo resaltado: cuánto del color principal (por ciento)\nconst HIGHLIGHT_TINT_PERCENT = 8;\n// en celular la línea va pegada a la izquierda: sin la columna de enfrente que @mui/lab reserva por omisión\nconst LEFT_ALIGNED_TIMELINE = {m: 0, px: 0, py: 0.5, [`& .${timelineItemClasses.root}::before`]: {flex: 0, p: 0}};\nconst ALTERNATE_TIMELINE = {m: 0, px: 0, py: 0.5};\n\n/**\n * @param {object} props\n * @param {Object[]} props.groups\n * @param {string} props.groups[].key\n * @param {string} [props.groups[].title] texto ya traducido; sin título el grupo no pinta encabezado\n * @param {string} [props.groups[].badge] insignia junto al título (p. ej. «Intento actual»)\n * @param {string} [props.groups[].summary] lo que se lee junto al título del grupo plegado (p. ej. «6 eventos»)\n * @param {boolean} [props.groups[].isCollapsible] el título se vuelve un botón que abre y cierra el grupo (necesita\n * title)\n * @param {boolean} [props.groups[].defaultExpanded] si un grupo plegable arranca abierto (por omisión, sí)\n * @param {'highlighted'|'normal'|'muted'} [props.groups[].emphasis]\n * @param {Object[]} props.groups[].items\n * @param {string} props.groups[].items[].key\n * @param {import('react').ElementType} [props.groups[].items[].icon] ícono dentro del punto\n * @param {string} [props.groups[].items[].tone] success, warning, error, info, primary o grey\n * @param {import('react').ReactNode} props.groups[].items[].title\n * @param {string} [props.groups[].items[].timestamp] fecha y hora ya formateadas\n * @param {import('react').ReactNode} [props.groups[].items[].details] lo que va abajo del título (chip de resultado, una liga...)\n */\nexport default function GroupedTimeline({groups}) {\n const theme = useTheme();\n const isWide = useMediaQuery(theme.breakpoints.up('md'));\n // llaves de los grupos plegables que el usuario tiene abiertos; arrancan como dice defaultExpanded\n const [expandedKeys, setExpandedKeys] = useState(() => new Set(\n groups.filter((timelineGroup) => timelineGroup.defaultExpanded !== false).map((timelineGroup) => timelineGroup.key),\n ));\n const toggleGroup = (groupKey) => setExpandedKeys((currentKeys) => {\n const nextKeys = new Set(currentKeys);\n if (nextKeys.has(groupKey)) {\n nextKeys.delete(groupKey);\n } else {\n nextKeys.add(groupKey);\n }\n return nextKeys;\n });\n\n return (\n <Stack spacing={1.5}>\n {groups.map((timelineGroup) => {\n const emphasis = timelineGroup.emphasis ?? TIMELINE_EMPHASIS.normal;\n const isHighlighted = emphasis === TIMELINE_EMPHASIS.highlighted;\n const isMuted = emphasis === TIMELINE_EMPHASIS.muted;\n const isCollapsible = Boolean(timelineGroup.isCollapsible && timelineGroup.title);\n const isExpanded = !isCollapsible || expandedKeys.has(timelineGroup.key);\n\n return (\n // el borde transparente en los demás grupos mantiene todo alineado con el grupo resaltado\n <Box key={timelineGroup.key} sx={{\n border: 1, borderRadius: 1.5, px: 1.5, pt: 1.25, pb: isExpanded ? 0 : 1.25,\n borderColor: isHighlighted ? 'primary.main' : 'transparent',\n // un tinte del color principal: primary.lighter no existe en el tema de MUI y el grupo se quedaba sin fondo\n bgcolor: (theme) => (isHighlighted ? `color-mix(in srgb, ${paletteOf(theme).primary.main} ${HIGHLIGHT_TINT_PERCENT}%, transparent)` : 'transparent'),\n }}>\n {timelineGroup.title && (\n <Stack direction=\"row\" spacing={1} sx={{alignItems: 'center', justifyContent: isWide ? 'center' : 'flex-start'}}>\n <ButtonBase disabled={!isCollapsible} onClick={() => toggleGroup(timelineGroup.key)}\n aria-expanded={isCollapsible ? isExpanded : undefined}\n sx={{gap: 1, px: 1, py: 0.25, borderRadius: 1, '&.Mui-disabled': {pointerEvents: 'none'}}}>\n <Typography variant=\"h6\" component=\"h3\" sx={{fontWeight: 700, color: isMuted ? 'text.secondary' : 'text.primary'}}>\n {timelineGroup.title}\n </Typography>\n {/* plegado, el grupo dice cuántos eventos trae: se sabe qué hay sin abrirlo */}\n {isCollapsible && timelineGroup.summary && (\n <Typography variant=\"body2\" color=\"text.secondary\" component=\"span\">{timelineGroup.summary}</Typography>\n )}\n {isCollapsible && (\n <ExpandMoreIcon fontSize=\"small\" sx={{\n color: 'text.secondary', transition: theme.transitions.create('transform'),\n transform: isExpanded ? 'rotate(180deg)' : 'none',\n }} />\n )}\n </ButtonBase>\n {timelineGroup.badge && <Chip size=\"small\" color=\"primary\" label={timelineGroup.badge} />}\n </Stack>\n )}\n <Collapse in={isExpanded} unmountOnExit>\n <Timeline position={isWide ? 'alternate' : 'right'} sx={isWide ? ALTERNATE_TIMELINE : LEFT_ALIGNED_TIMELINE}>\n {timelineGroup.items.map((timelineEntry, entryPosition) => {\n const EntryIcon = timelineEntry.icon;\n const isFirstEntry = entryPosition === 0;\n const isLastEntry = entryPosition === timelineGroup.items.length - 1;\n\n return (\n <TimelineItem key={timelineEntry.key}>\n {isWide && (\n <TimelineOppositeContent variant=\"body2\" color=\"text.secondary\" sx={{m: 'auto 0'}}>\n {timelineEntry.timestamp}\n </TimelineOppositeContent>\n )}\n <TimelineSeparator>\n <TimelineConnector sx={{visibility: isFirstEntry ? 'hidden' : 'visible'}} />\n <TimelineDot {...timelineDotOf({emphasis, tone: timelineEntry.tone})}>\n {EntryIcon && <EntryIcon fontSize=\"small\" />}\n </TimelineDot>\n <TimelineConnector sx={{visibility: isLastEntry ? 'hidden' : 'visible'}} />\n </TimelineSeparator>\n <TimelineContent sx={{py: 1.5, px: 2, minWidth: 0}}>\n <Typography variant=\"body2\" component=\"p\" sx={{fontWeight: 600, color: isMuted ? 'text.secondary' : 'text.primary'}}>\n {timelineEntry.title}\n </Typography>\n {!isWide && timelineEntry.timestamp && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\">{timelineEntry.timestamp}</Typography>\n )}\n {timelineEntry.details}\n </TimelineContent>\n </TimelineItem>\n );\n })}\n </Timeline>\n </Collapse>\n </Box>\n );\n })}\n </Stack>\n );\n}\n"],"names":["theme"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GroupedTimeline.js","sources":["../../../src/ui/timeline/GroupedTimeline.jsx"],"sourcesContent":["// Línea de tiempo por grupos (Timeline de @mui/lab al estilo del ejemplo «Customization» de MUI): cada grupo con su\n// título y una insignia opcional, y cada evento con su ícono dentro del punto, su título, su hora y un detalle libre.\n//\n// Uso típico: el historial de un registro agrupado por etapa o por intento (detalle de un pedido: un grupo por intento de entrega,\n// el vigente resaltado). El énfasis de cada grupo (TIMELINE_EMPHASIS) decide cómo se pintan sus puntos (timelineDot.js).\n//\n// En pantalla ancha los eventos alternan de lado y la hora va del otro lado del punto; en celular todo va de un lado, con\n// la hora abajo del título, para que quepa.\n//\n// Un grupo plegable (isCollapsible) enseña solo su título y su resumen hasta que se abre: sirve para que lo viejo no\n// obligue a bajar (los intentos anteriores van plegados).\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: títulos, horas y detalles llegan ya traducidos y\n// formateados, y el ícono y el tono de cada evento los decide quien la usa (con sus diccionarios).\nimport {useState} from 'react';\nimport Timeline from '@mui/lab/Timeline';\nimport TimelineConnector from '@mui/lab/TimelineConnector';\nimport TimelineContent from '@mui/lab/TimelineContent';\nimport TimelineDot from '@mui/lab/TimelineDot';\nimport TimelineItem, {timelineItemClasses} from '@mui/lab/TimelineItem';\nimport TimelineOppositeContent from '@mui/lab/TimelineOppositeContent';\nimport TimelineSeparator from '@mui/lab/TimelineSeparator';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Chip from '@mui/material/Chip';\nimport Collapse from '@mui/material/Collapse';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport useMediaQuery from '@mui/material/useMediaQuery';\nimport {useTheme} from '@mui/material/styles';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\n\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {TIMELINE_EMPHASIS, timelineDotOf} from '@/ui/timeline/timelineDot.js';\n\n// el fondo del grupo resaltado: cuánto del color principal (por ciento)\nconst HIGHLIGHT_TINT_PERCENT = 8;\n// en celular la línea va pegada a la izquierda: sin la columna de enfrente que @mui/lab reserva por omisión\nconst LEFT_ALIGNED_TIMELINE = {m: 0, px: 0, py: 0.5, [`& .${timelineItemClasses.root}::before`]: {flex: 0, p: 0}};\nconst ALTERNATE_TIMELINE = {m: 0, px: 0, py: 0.5};\n\n/**\n * @param {object} props\n * @param {Object[]} props.groups\n * @param {string} props.groups[].key\n * @param {string} [props.groups[].title] texto ya traducido; sin título el grupo no pinta encabezado\n * @param {string} [props.groups[].badge] insignia junto al título (p. ej. «Intento actual»)\n * @param {string} [props.groups[].summary] lo que se lee junto al título del grupo plegado (p. ej. «6 eventos»)\n * @param {boolean} [props.groups[].isCollapsible] el título se vuelve un botón que abre y cierra el grupo (necesita\n * title)\n * @param {boolean} [props.groups[].defaultExpanded] si un grupo plegable arranca abierto (por omisión, sí)\n * @param {'highlighted'|'normal'|'muted'} [props.groups[].emphasis]\n * @param {Object[]} props.groups[].items\n * @param {string} props.groups[].items[].key\n * @param {import('react').ElementType} [props.groups[].items[].icon] ícono dentro del punto\n * @param {string} [props.groups[].items[].tone] success, warning, error, info, primary o grey\n * @param {import('react').ReactNode} props.groups[].items[].title\n * @param {string} [props.groups[].items[].timestamp] fecha y hora ya formateadas\n * @param {import('react').ReactNode} [props.groups[].items[].details] lo que va abajo del título (chip de resultado, una liga...)\n * @param {(groupKey: string, isExpanded: boolean) => void} [props.onGroupToggle] la persona abrió o plegó un grupo (por ejemplo,\n * para pedir sus eventos hasta que se abre)\n */\nexport default function GroupedTimeline({groups, onGroupToggle}) {\n const theme = useTheme();\n const isWide = useMediaQuery(theme.breakpoints.up('md'));\n // llaves de los grupos plegables que el usuario tiene abiertos; arrancan como dice defaultExpanded\n const [expandedKeys, setExpandedKeys] = useState(() => new Set(\n groups.filter((timelineGroup) => timelineGroup.defaultExpanded !== false).map((timelineGroup) => timelineGroup.key),\n ));\n const toggleGroup = (groupKey) => {\n const isOpening = !expandedKeys.has(groupKey);\n const nextKeys = new Set(expandedKeys);\n if (isOpening) {\n nextKeys.add(groupKey);\n } else {\n nextKeys.delete(groupKey);\n }\n setExpandedKeys(nextKeys);\n onGroupToggle?.(groupKey, isOpening);\n };\n\n return (\n <Stack spacing={1.5}>\n {groups.map((timelineGroup) => {\n const emphasis = timelineGroup.emphasis ?? TIMELINE_EMPHASIS.normal;\n const isHighlighted = emphasis === TIMELINE_EMPHASIS.highlighted;\n const isMuted = emphasis === TIMELINE_EMPHASIS.muted;\n const isCollapsible = Boolean(timelineGroup.isCollapsible && timelineGroup.title);\n const isExpanded = !isCollapsible || expandedKeys.has(timelineGroup.key);\n\n return (\n // el borde transparente en los demás grupos mantiene todo alineado con el grupo resaltado\n <Box key={timelineGroup.key} sx={{\n border: 1, borderRadius: 1.5, px: 1.5, pt: 1.25, pb: isExpanded ? 0 : 1.25,\n borderColor: isHighlighted ? 'primary.main' : 'transparent',\n // un tinte del color principal: primary.lighter no existe en el tema de MUI y el grupo se quedaba sin fondo\n bgcolor: (theme) => (isHighlighted ? `color-mix(in srgb, ${paletteOf(theme).primary.main} ${HIGHLIGHT_TINT_PERCENT}%, transparent)` : 'transparent'),\n }}>\n {timelineGroup.title && (\n <Stack direction=\"row\" spacing={1} sx={{alignItems: 'center', justifyContent: isWide ? 'center' : 'flex-start'}}>\n <ButtonBase disabled={!isCollapsible} onClick={() => toggleGroup(timelineGroup.key)}\n aria-expanded={isCollapsible ? isExpanded : undefined}\n sx={{gap: 1, px: 1, py: 0.25, borderRadius: 1, '&.Mui-disabled': {pointerEvents: 'none'}}}>\n <Typography variant=\"h6\" component=\"h3\" sx={{fontWeight: 700, color: isMuted ? 'text.secondary' : 'text.primary'}}>\n {timelineGroup.title}\n </Typography>\n {/* plegado, el grupo dice cuántos eventos trae: se sabe qué hay sin abrirlo */}\n {isCollapsible && timelineGroup.summary && (\n <Typography variant=\"body2\" color=\"text.secondary\" component=\"span\">{timelineGroup.summary}</Typography>\n )}\n {isCollapsible && (\n <ExpandMoreIcon fontSize=\"small\" sx={{\n color: 'text.secondary', transition: theme.transitions.create('transform'),\n transform: isExpanded ? 'rotate(180deg)' : 'none',\n }} />\n )}\n </ButtonBase>\n {timelineGroup.badge && <Chip size=\"small\" color=\"primary\" label={timelineGroup.badge} />}\n </Stack>\n )}\n <Collapse in={isExpanded} unmountOnExit>\n <Timeline position={isWide ? 'alternate' : 'right'} sx={isWide ? ALTERNATE_TIMELINE : LEFT_ALIGNED_TIMELINE}>\n {timelineGroup.items.map((timelineEntry, entryPosition) => {\n const EntryIcon = timelineEntry.icon;\n const isFirstEntry = entryPosition === 0;\n const isLastEntry = entryPosition === timelineGroup.items.length - 1;\n\n return (\n <TimelineItem key={timelineEntry.key}>\n {isWide && (\n <TimelineOppositeContent variant=\"body2\" color=\"text.secondary\" sx={{m: 'auto 0'}}>\n {timelineEntry.timestamp}\n </TimelineOppositeContent>\n )}\n <TimelineSeparator>\n <TimelineConnector sx={{visibility: isFirstEntry ? 'hidden' : 'visible'}} />\n <TimelineDot {...timelineDotOf({emphasis, tone: timelineEntry.tone})}>\n {EntryIcon && <EntryIcon fontSize=\"small\" />}\n </TimelineDot>\n <TimelineConnector sx={{visibility: isLastEntry ? 'hidden' : 'visible'}} />\n </TimelineSeparator>\n <TimelineContent sx={{py: 1.5, px: 2, minWidth: 0}}>\n <Typography variant=\"body2\" component=\"p\" sx={{fontWeight: 600, color: isMuted ? 'text.secondary' : 'text.primary'}}>\n {timelineEntry.title}\n </Typography>\n {!isWide && timelineEntry.timestamp && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\">{timelineEntry.timestamp}</Typography>\n )}\n {timelineEntry.details}\n </TimelineContent>\n </TimelineItem>\n );\n })}\n </Timeline>\n </Collapse>\n </Box>\n );\n })}\n </Stack>\n );\n}\n"],"names":["theme"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,MAAM,yBAAyB;AAE/B,MAAM,wBAAwB,EAAC,GAAG,GAAG,IAAI,GAAG,IAAI,KAAK,CAAC,MAAM,oBAAoB,IAAI,UAAU,GAAG,EAAC,MAAM,GAAG,GAAG,IAAC;AAC/G,MAAM,qBAAqB,EAAC,GAAG,GAAG,IAAI,GAAG,IAAI,IAAA;AAuB7C,SAAwB,gBAAgB,EAAC,QAAQ,iBAAgB;AAC7D,QAAM,QAAQ,SAAA;AACd,QAAM,SAAS,cAAc,MAAM,YAAY,GAAG,IAAI,CAAC;AAEvD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,MAAM,IAAI;AAAA,IACvD,OAAO,OAAO,CAAC,kBAAkB,cAAc,oBAAoB,KAAK,EAAE,IAAI,CAAC,kBAAkB,cAAc,GAAG;AAAA,EAAA,CACrH;AACD,QAAM,cAAc,CAAC,aAAa;AAC9B,UAAM,YAAY,CAAC,aAAa,IAAI,QAAQ;AAC5C,UAAM,WAAW,IAAI,IAAI,YAAY;AACrC,QAAI,WAAW;AACX,eAAS,IAAI,QAAQ;AAAA,IACzB,OAAO;AACH,eAAS,OAAO,QAAQ;AAAA,IAC5B;AACA,oBAAgB,QAAQ;AACxB,oBAAgB,UAAU,SAAS;AAAA,EACvC;AAEA,6BACK,OAAA,EAAM,SAAS,KACX,UAAA,OAAO,IAAI,CAAC,kBAAkB;AAC3B,UAAM,WAAW,cAAc,YAAY,kBAAkB;AAC7D,UAAM,gBAAgB,aAAa,kBAAkB;AACrD,UAAM,UAAU,aAAa,kBAAkB;AAC/C,UAAM,gBAAgB,QAAQ,cAAc,iBAAiB,cAAc,KAAK;AAChF,UAAM,aAAa,CAAC,iBAAiB,aAAa,IAAI,cAAc,GAAG;AAEvE;AAAA;AAAA,MAEI,qBAAC,OAA4B,IAAI;AAAA,QAC7B,QAAQ;AAAA,QAAG,cAAc;AAAA,QAAK,IAAI;AAAA,QAAK,IAAI;AAAA,QAAM,IAAI,aAAa,IAAI;AAAA,QACtE,aAAa,gBAAgB,iBAAiB;AAAA;AAAA,QAE9C,SAAS,CAACA,WAAW,gBAAgB,sBAAsB,UAAUA,MAAK,EAAE,QAAQ,IAAI,IAAI,sBAAsB,oBAAoB;AAAA,MAAA,GAErI,UAAA;AAAA,QAAA,cAAc,SACX,qBAAC,OAAA,EAAM,WAAU,OAAM,SAAS,GAAG,IAAI,EAAC,YAAY,UAAU,gBAAgB,SAAS,WAAW,gBAC9F,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAW,UAAU,CAAC;AAAA,cAAe,SAAS,MAAM,YAAY,cAAc,GAAG;AAAA,cACtE,iBAAe,gBAAgB,aAAa;AAAA,cAC5C,IAAI,EAAC,KAAK,GAAG,IAAI,GAAG,IAAI,MAAM,cAAc,GAAG,kBAAkB,EAAC,eAAe,SAAM;AAAA,cAC/F,UAAA;AAAA,gBAAA,oBAAC,YAAA,EAAW,SAAQ,MAAK,WAAU,MAAK,IAAI,EAAC,YAAY,KAAK,OAAO,UAAU,mBAAmB,eAAA,GAC7F,wBAAc,OACnB;AAAA,gBAEC,iBAAiB,cAAc,WAC5B,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,WAAU,QAAQ,UAAA,cAAc,SAAQ;AAAA,gBAE9F,iBACG,oBAAC,gBAAA,EAAe,UAAS,SAAQ,IAAI;AAAA,kBACjC,OAAO;AAAA,kBAAkB,YAAY,MAAM,YAAY,OAAO,WAAW;AAAA,kBACzE,WAAW,aAAa,mBAAmB;AAAA,gBAAA,EAC/C,CAAG;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGV,cAAc,SAAS,oBAAC,MAAA,EAAK,MAAK,SAAQ,OAAM,WAAU,OAAO,cAAc,MAAA,CAAO;AAAA,QAAA,GAC3F;AAAA,QAEJ,oBAAC,YAAS,IAAI,YAAY,eAAa,MACnC,UAAA,oBAAC,YAAS,UAAU,SAAS,cAAc,SAAS,IAAI,SAAS,qBAAqB,uBACjF,wBAAc,MAAM,IAAI,CAAC,eAAe,kBAAkB;AACvD,gBAAM,YAAY,cAAc;AAChC,gBAAM,eAAe,kBAAkB;AACvC,gBAAM,cAAc,kBAAkB,cAAc,MAAM,SAAS;AAEnE,sCACK,cAAA,EACI,UAAA;AAAA,YAAA,UACG,oBAAC,yBAAA,EAAwB,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAC,GAAG,SAAA,GACnE,UAAA,cAAc,WACnB;AAAA,iCAEH,mBAAA,EACG,UAAA;AAAA,cAAA,oBAAC,qBAAkB,IAAI,EAAC,YAAY,eAAe,WAAW,aAAY;AAAA,kCACzE,aAAA,EAAa,GAAG,cAAc,EAAC,UAAU,MAAM,cAAc,KAAA,CAAK,GAC9D,UAAA,aAAa,oBAAC,WAAA,EAAU,UAAS,SAAQ,GAC9C;AAAA,cACA,oBAAC,qBAAkB,IAAI,EAAC,YAAY,cAAc,WAAW,YAAS,CAAG;AAAA,YAAA,GAC7E;AAAA,YACA,qBAAC,iBAAA,EAAgB,IAAI,EAAC,IAAI,KAAK,IAAI,GAAG,UAAU,EAAA,GAC5C,UAAA;AAAA,cAAA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,WAAU,KAAI,IAAI,EAAC,YAAY,KAAK,OAAO,UAAU,mBAAmB,eAAA,GAC/F,wBAAc,OACnB;AAAA,cACC,CAAC,UAAU,cAAc,aACtB,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,WAAU,KAAK,wBAAc,WAAU;AAAA,cAE/F,cAAc;AAAA,YAAA,EAAA,CACnB;AAAA,UAAA,EAAA,GArBe,cAAc,GAsBjC;AAAA,QAER,CAAC,GACL,EAAA,CACJ;AAAA,MAAA,EAAA,GA9DM,cAAc,GA+DxB;AAAA;AAAA,EAER,CAAC,EAAA,CACL;AAER;"}
|
|
@@ -16,7 +16,7 @@ import PictureAsPdfOutlinedIcon from "@mui/icons-material/PictureAsPdfOutlined";
|
|
|
16
16
|
import TableViewOutlinedIcon from "@mui/icons-material/TableViewOutlined";
|
|
17
17
|
import ModalWaiting from "../feedback/ModalWaiting.js";
|
|
18
18
|
import { toastError } from "../feedback/toast.js";
|
|
19
|
-
import {
|
|
19
|
+
import { useFormatters } from "../toolkit/useFormatters.js";
|
|
20
20
|
import { resolveAccept, parseFileSize, matchesAccept, FILE_REJECTION } from "./fileRules.js";
|
|
21
21
|
const FILE_APPEARANCES = [
|
|
22
22
|
{ pattern: /\.(xlsx?|csv)$/, Icon: TableViewOutlinedIcon, color: "success" },
|
|
@@ -38,9 +38,11 @@ function FileDropzone({
|
|
|
38
38
|
onReject,
|
|
39
39
|
actions,
|
|
40
40
|
children,
|
|
41
|
-
sx
|
|
41
|
+
sx,
|
|
42
|
+
texts
|
|
42
43
|
}) {
|
|
43
|
-
const { t } = useToolkitTranslation("common");
|
|
44
|
+
const { t } = useToolkitTranslation("common", texts);
|
|
45
|
+
const { formatFileSize } = useFormatters();
|
|
44
46
|
const inputRef = useRef(null);
|
|
45
47
|
const [isDragging, setIsDragging] = useState(false);
|
|
46
48
|
const isLocked = disabled || busy;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDropzone.js","sources":["../../src/upload/FileDropzone.jsx"],"sourcesContent":["// La zona para soltar UN archivo, con puro MUI (sin librerías): se suelta o se elige, se revisa su tipo y su peso, y el\n// elegido se ve con su ícono, su nombre y su peso, con la × para quitarlo sin volver a abrir la ventana de archivos.\n//\n// Hay otra con el mismo uso y FilePond por dentro (@stackcraftmx/calcita/filepond): animaciones, varios archivos y\n// avance por archivo. Cambiar de una a otra es cambiar el import.\n//\n// Solo ELIGE el archivo (controlado: value / onChange). Enviarlo es de la pantalla: arma su FormData con los campos que\n// pida su backend y lo sube (uploadWithProgress + uploadMachine). Para eso están los huecos:\n// actions botones junto a «Elegir archivo» (p. ej. el de enviar)\n// children lo que va abajo (campos del formulario, el avance de la subida)\n//\n// Configuración: accept y maxSize (upload/fileRules.js); busy pone el candado mientras se sube (no se puede quitar ni\n// cambiar el archivo a media subida) y busyModal además bloquea toda la pantalla con ModalWaiting.\n//\n// Lo que se rechaza se avisa con toastError y los textos del paquete; con onReject la pantalla decide qué hacer.\n//\n// Mobile primero: en el teléfono no hay arrastrar; el botón es el camino y los botones se apilan a lo ancho.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useRef, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined';\nimport ImageOutlinedIcon from '@mui/icons-material/ImageOutlined';\nimport InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';\nimport PictureAsPdfOutlinedIcon from '@mui/icons-material/PictureAsPdfOutlined';\nimport TableViewOutlinedIcon from '@mui/icons-material/TableViewOutlined';\n\nimport ModalWaiting from '@/feedback/ModalWaiting.jsx';\nimport {toastError} from '@/feedback/toast.jsx';\nimport {formatFileSize} from '@/formatting.js';\nimport {FILE_REJECTION, matchesAccept, parseFileSize, resolveAccept} from '@/upload/fileRules.js';\n\n// el ícono según el tipo del archivo elegido, con el mismo color que el panel de descargas\nconst FILE_APPEARANCES = [\n {pattern: /\\.(xlsx?|csv)$/, Icon: TableViewOutlinedIcon, color: 'success'},\n {pattern: /\\.pdf$/, Icon: PictureAsPdfOutlinedIcon, color: 'error'},\n {pattern: /\\.(png|jpe?g|gif|webp|svg|avif)$/, Icon: ImageOutlinedIcon, color: 'info'},\n {pattern: /\\.(docx?|txt|md)$/, Icon: DescriptionOutlinedIcon, color: 'primary'},\n];\nconst DEFAULT_FILE_APPEARANCE = {Icon: InsertDriveFileOutlinedIcon, color: 'action'};\n\n/**\n * @param {object} props\n * @param {File|null} [props.value] el archivo elegido\n * @param {(file: File|null) => void} props.onChange null al quitarlo\n * @param {string|string[]} [props.accept] 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'\n * @param {number|string} [props.maxSize] bytes o '10 MB'\n * @param {string} [props.hint] ya traducido; por omisión «Arrastre aquí su archivo»\n * @param {string} [props.buttonLabel] ya traducido; por omisión «Elegir archivo»\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.busy] candado mientras se sube: no se puede soltar, elegir ni quitar\n * @param {boolean|{title?: string, text?: string}} [props.busyModal] además bloquea la pantalla mientras busy\n * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso\n * @param {import('react').ReactNode} [props.actions]\n * @param {import('react').ReactNode} [props.children]\n * @param {object} [props.sx] ajustes del recuadro\n */\nexport default function FileDropzone({\n value = null, onChange, accept, maxSize, hint, buttonLabel, disabled = false, busy = false, busyModal = false, onReject, actions,\n children, sx,\n}) {\n const {t} = useToolkitTranslation('common');\n const inputRef = useRef(null);\n const [isDragging, setIsDragging] = useState(false);\n const isLocked = disabled || busy;\n const resolvedAccept = resolveAccept(accept);\n const maxBytes = parseFileSize(maxSize);\n const hintText = hint ?? t('upload.hint');\n\n const reject = (file, reason) => {\n if (onReject) {\n onReject(file, reason);\n return;\n }\n const message = reason === FILE_REJECTION.size\n ? t('upload.tooLarge', {name: file.name, max: formatFileSize(maxBytes)})\n : t('upload.invalidType', {name: file.name, accept: resolvedAccept});\n toastError(message);\n };\n\n const pick = (file) => {\n // guard clause: se cerró la ventana sin elegir, o el candado está puesto\n if (!file || isLocked) {\n return;\n }\n if (!matchesAccept(file, resolvedAccept)) {\n reject(file, FILE_REJECTION.type);\n return;\n }\n if (maxBytes && file.size > maxBytes) {\n reject(file, FILE_REJECTION.size);\n return;\n }\n onChange(file);\n };\n\n const openPicker = () => {\n // OJO: se limpia el valor del input para poder volver a elegir EL MISMO archivo (corregido en disco); sin esto\n // el navegador no avisa el cambio\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n inputRef.current?.click();\n };\n\n const appearance = value\n ? FILE_APPEARANCES.find(({pattern}) => pattern.test(value.name.toLowerCase())) ?? DEFAULT_FILE_APPEARANCE\n : null;\n\n return (\n <Paper\n variant=\"outlined\"\n aria-busy={busy}\n onDragOver={(event) => {\n event.preventDefault();\n setIsDragging(!isLocked);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={(event) => {\n event.preventDefault();\n setIsDragging(false);\n pick(event.dataTransfer.files?.[0]);\n }}\n sx={{\n p: {xs: 3, sm: 5},\n textAlign: 'center',\n borderStyle: 'dashed',\n borderWidth: 2,\n borderColor: isDragging ? 'primary.main' : 'divider',\n bgcolor: isDragging ? 'action.hover' : 'background.paper',\n transition: 'border-color .15s ease, background-color .15s ease',\n opacity: disabled ? 0.6 : 1,\n ...sx,\n }}\n >\n <input ref={inputRef} type=\"file\" accept={resolvedAccept} hidden disabled={isLocked} aria-label={hintText}\n onChange={(event) => pick(event.target.files?.[0])} />\n {value ? (\n <Box sx={{mb: 2}}>\n <Chip\n icon={<appearance.Icon fontSize=\"small\" color={appearance.color} />}\n label={`${value.name} · ${formatFileSize(value.size)}`}\n variant=\"outlined\"\n onDelete={isLocked ? undefined : () => onChange(null)}\n deleteIcon={<CancelIcon aria-label={t('upload.remove', {name: value.name})} />}\n sx={{maxWidth: '100%', height: 'auto', py: 0.5, '& .MuiChip-label': {whiteSpace: 'normal', overflowWrap: 'anywhere'}}}\n />\n </Box>\n ) : (\n <Typography variant=\"body1\" sx={{mb: 2, overflowWrap: 'anywhere'}}>{hintText}</Typography>\n )}\n <Stack direction={{xs: 'column', sm: 'row'}} spacing={2} sx={{justifyContent: 'center', alignItems: {xs: 'stretch', sm: 'center'}}}>\n <Button variant=\"outlined\" onClick={openPicker} disabled={isLocked}>{buttonLabel ?? t('upload.choose')}</Button>\n {actions}\n </Stack>\n {/* el límite, discreto, solo si hay límite */}\n {maxBytes && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{display: 'block', mt: 1.5}}>\n {t('upload.maxSizeHint', {max: formatFileSize(maxBytes)})}\n </Typography>\n )}\n {children && <Box sx={{mt: 3, textAlign: 'left'}}>{children}</Box>}\n {busyModal && <ModalWaiting open={busy} title={busyModal.title} text={busyModal.text} />}\n </Paper>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileDropzone.js","sources":["../../src/upload/FileDropzone.jsx"],"sourcesContent":["// La zona para soltar UN archivo, con puro MUI (sin librerías): se suelta o se elige, se revisa su tipo y su peso, y el\n// elegido se ve con su ícono, su nombre y su peso, con la × para quitarlo sin volver a abrir la ventana de archivos.\n//\n// Hay otra con el mismo uso y FilePond por dentro (@stackcraftmx/calcita/filepond): animaciones, varios archivos y\n// avance por archivo. Cambiar de una a otra es cambiar el import.\n//\n// Solo ELIGE el archivo (controlado: value / onChange). Enviarlo es de la pantalla: arma su FormData con los campos que\n// pida su backend y lo sube (uploadWithProgress + uploadMachine). Para eso están los huecos:\n// actions botones junto a «Elegir archivo» (p. ej. el de enviar)\n// children lo que va abajo (campos del formulario, el avance de la subida)\n//\n// Configuración: accept y maxSize (upload/fileRules.js); busy pone el candado mientras se sube (no se puede quitar ni\n// cambiar el archivo a media subida) y busyModal además bloquea toda la pantalla con ModalWaiting.\n//\n// Lo que se rechaza se avisa con toastError y los textos del paquete; con onReject la pantalla decide qué hacer.\n//\n// Mobile primero: en el teléfono no hay arrastrar; el botón es el camino y los botones se apilan a lo ancho.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useRef, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Chip from '@mui/material/Chip';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport CancelIcon from '@mui/icons-material/Cancel';\nimport DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined';\nimport ImageOutlinedIcon from '@mui/icons-material/ImageOutlined';\nimport InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';\nimport PictureAsPdfOutlinedIcon from '@mui/icons-material/PictureAsPdfOutlined';\nimport TableViewOutlinedIcon from '@mui/icons-material/TableViewOutlined';\n\nimport ModalWaiting from '@/feedback/ModalWaiting.jsx';\nimport {toastError} from '@/feedback/toast.jsx';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {FILE_REJECTION, matchesAccept, parseFileSize, resolveAccept} from '@/upload/fileRules.js';\n\n// el ícono según el tipo del archivo elegido, con el mismo color que el panel de descargas\nconst FILE_APPEARANCES = [\n {pattern: /\\.(xlsx?|csv)$/, Icon: TableViewOutlinedIcon, color: 'success'},\n {pattern: /\\.pdf$/, Icon: PictureAsPdfOutlinedIcon, color: 'error'},\n {pattern: /\\.(png|jpe?g|gif|webp|svg|avif)$/, Icon: ImageOutlinedIcon, color: 'info'},\n {pattern: /\\.(docx?|txt|md)$/, Icon: DescriptionOutlinedIcon, color: 'primary'},\n];\nconst DEFAULT_FILE_APPEARANCE = {Icon: InsertDriveFileOutlinedIcon, color: 'action'};\n\n/**\n * @param {object} props\n * @param {File|null} [props.value] el archivo elegido\n * @param {(file: File|null) => void} props.onChange null al quitarlo\n * @param {string|string[]} [props.accept] 'excel' | ['excel', 'pdf'] | '.xlsx,.xls' | 'image/*'\n * @param {number|string} [props.maxSize] bytes o '10 MB'\n * @param {string} [props.hint] ya traducido; por omisión «Arrastre aquí su archivo»\n * @param {string} [props.buttonLabel] ya traducido; por omisión «Elegir archivo»\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.busy] candado mientras se sube: no se puede soltar, elegir ni quitar\n * @param {boolean|{title?: string, text?: string}} [props.busyModal] además bloquea la pantalla mientras busy\n * @param {(file: File, reason: string) => void} [props.onReject] reason es uno de FILE_REJECTION; sin él, un aviso\n * @param {import('react').ReactNode} [props.actions]\n * @param {import('react').ReactNode} [props.children]\n * @param {object} [props.sx] ajustes del recuadro\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function FileDropzone({\n value = null, onChange, accept, maxSize, hint, buttonLabel, disabled = false, busy = false, busyModal = false, onReject, actions,\n children, sx, texts,\n}) {\n const {t} = useToolkitTranslation('common', texts);\n const {formatFileSize} = useFormatters();\n const inputRef = useRef(null);\n const [isDragging, setIsDragging] = useState(false);\n const isLocked = disabled || busy;\n const resolvedAccept = resolveAccept(accept);\n const maxBytes = parseFileSize(maxSize);\n const hintText = hint ?? t('upload.hint');\n\n const reject = (file, reason) => {\n if (onReject) {\n onReject(file, reason);\n return;\n }\n const message = reason === FILE_REJECTION.size\n ? t('upload.tooLarge', {name: file.name, max: formatFileSize(maxBytes)})\n : t('upload.invalidType', {name: file.name, accept: resolvedAccept});\n toastError(message);\n };\n\n const pick = (file) => {\n // guard clause: se cerró la ventana sin elegir, o el candado está puesto\n if (!file || isLocked) {\n return;\n }\n if (!matchesAccept(file, resolvedAccept)) {\n reject(file, FILE_REJECTION.type);\n return;\n }\n if (maxBytes && file.size > maxBytes) {\n reject(file, FILE_REJECTION.size);\n return;\n }\n onChange(file);\n };\n\n const openPicker = () => {\n // OJO: se limpia el valor del input para poder volver a elegir EL MISMO archivo (corregido en disco); sin esto\n // el navegador no avisa el cambio\n if (inputRef.current) {\n inputRef.current.value = '';\n }\n inputRef.current?.click();\n };\n\n const appearance = value\n ? FILE_APPEARANCES.find(({pattern}) => pattern.test(value.name.toLowerCase())) ?? DEFAULT_FILE_APPEARANCE\n : null;\n\n return (\n <Paper\n variant=\"outlined\"\n aria-busy={busy}\n onDragOver={(event) => {\n event.preventDefault();\n setIsDragging(!isLocked);\n }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={(event) => {\n event.preventDefault();\n setIsDragging(false);\n pick(event.dataTransfer.files?.[0]);\n }}\n sx={{\n p: {xs: 3, sm: 5},\n textAlign: 'center',\n borderStyle: 'dashed',\n borderWidth: 2,\n borderColor: isDragging ? 'primary.main' : 'divider',\n bgcolor: isDragging ? 'action.hover' : 'background.paper',\n transition: 'border-color .15s ease, background-color .15s ease',\n opacity: disabled ? 0.6 : 1,\n ...sx,\n }}\n >\n <input ref={inputRef} type=\"file\" accept={resolvedAccept} hidden disabled={isLocked} aria-label={hintText}\n onChange={(event) => pick(event.target.files?.[0])} />\n {value ? (\n <Box sx={{mb: 2}}>\n <Chip\n icon={<appearance.Icon fontSize=\"small\" color={appearance.color} />}\n label={`${value.name} · ${formatFileSize(value.size)}`}\n variant=\"outlined\"\n onDelete={isLocked ? undefined : () => onChange(null)}\n deleteIcon={<CancelIcon aria-label={t('upload.remove', {name: value.name})} />}\n sx={{maxWidth: '100%', height: 'auto', py: 0.5, '& .MuiChip-label': {whiteSpace: 'normal', overflowWrap: 'anywhere'}}}\n />\n </Box>\n ) : (\n <Typography variant=\"body1\" sx={{mb: 2, overflowWrap: 'anywhere'}}>{hintText}</Typography>\n )}\n <Stack direction={{xs: 'column', sm: 'row'}} spacing={2} sx={{justifyContent: 'center', alignItems: {xs: 'stretch', sm: 'center'}}}>\n <Button variant=\"outlined\" onClick={openPicker} disabled={isLocked}>{buttonLabel ?? t('upload.choose')}</Button>\n {actions}\n </Stack>\n {/* el límite, discreto, solo si hay límite */}\n {maxBytes && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{display: 'block', mt: 1.5}}>\n {t('upload.maxSizeHint', {max: formatFileSize(maxBytes)})}\n </Typography>\n )}\n {children && <Box sx={{mt: 3, textAlign: 'left'}}>{children}</Box>}\n {busyModal && <ModalWaiting open={busy} title={busyModal.title} text={busyModal.text} />}\n </Paper>\n );\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackcraftmx/calcita",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Componentes y utilidades de React con MUI para arrancar proyectos rápido: tabla de servidor, diálogos, avisos, descargas, formularios, formatos y reportes en Excel.",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"author": "calcifux",
|
|
@@ -130,7 +130,8 @@
|
|
|
130
130
|
"./kanban": {
|
|
131
131
|
"types": "./dist/types/kanban.d.ts",
|
|
132
132
|
"import": "./dist/kanban.js"
|
|
133
|
-
}
|
|
133
|
+
},
|
|
134
|
+
"./package.json": "./package.json"
|
|
134
135
|
},
|
|
135
136
|
"scripts": {
|
|
136
137
|
"prepublishOnly": "pnpm run check",
|
|
@@ -144,9 +145,7 @@
|
|
|
144
145
|
"tunnel:status": "bash scripts/tunnel.sh status"
|
|
145
146
|
},
|
|
146
147
|
"dependencies": {
|
|
147
|
-
"
|
|
148
|
-
"uuid": "14.0.2",
|
|
149
|
-
"yup": "1.7.1"
|
|
148
|
+
"uuid": "14.0.2"
|
|
150
149
|
},
|
|
151
150
|
"peerDependencies": {
|
|
152
151
|
"@emotion/react": "^11.14.0",
|
|
@@ -170,6 +169,7 @@
|
|
|
170
169
|
"filepond": "^4.32.0",
|
|
171
170
|
"filepond-plugin-file-validate-size": "^2.2.8",
|
|
172
171
|
"filepond-plugin-file-validate-type": "^1.2.9",
|
|
172
|
+
"formik": "^2.4.0",
|
|
173
173
|
"leaflet": "^1.9.0",
|
|
174
174
|
"next": ">=15.0.0",
|
|
175
175
|
"nuqs": "^2.0.0",
|
|
@@ -181,7 +181,8 @@
|
|
|
181
181
|
"react-router": "^7.0.0",
|
|
182
182
|
"recharts": "^3.0.0",
|
|
183
183
|
"sonner": "^2.0.0",
|
|
184
|
-
"xstate": "^5.0.0"
|
|
184
|
+
"xstate": "^5.0.0",
|
|
185
|
+
"yup": "^1.4.0"
|
|
185
186
|
},
|
|
186
187
|
"peerDependenciesMeta": {
|
|
187
188
|
"@fullcalendar/core": {
|
|
@@ -232,6 +233,9 @@
|
|
|
232
233
|
"filepond-plugin-file-validate-type": {
|
|
233
234
|
"optional": true
|
|
234
235
|
},
|
|
236
|
+
"formik": {
|
|
237
|
+
"optional": true
|
|
238
|
+
},
|
|
235
239
|
"leaflet": {
|
|
236
240
|
"optional": true
|
|
237
241
|
},
|
|
@@ -255,6 +259,9 @@
|
|
|
255
259
|
},
|
|
256
260
|
"recharts": {
|
|
257
261
|
"optional": true
|
|
262
|
+
},
|
|
263
|
+
"yup": {
|
|
264
|
+
"optional": true
|
|
258
265
|
}
|
|
259
266
|
},
|
|
260
267
|
"devDependencies": {
|
|
@@ -285,6 +292,7 @@
|
|
|
285
292
|
"filepond": "4.32.12",
|
|
286
293
|
"filepond-plugin-file-validate-size": "2.2.8",
|
|
287
294
|
"filepond-plugin-file-validate-type": "1.2.9",
|
|
295
|
+
"formik": "2.4.9",
|
|
288
296
|
"leaflet": "1.9.4",
|
|
289
297
|
"next": "16.4.2",
|
|
290
298
|
"nuqs": "2.10.1",
|
|
@@ -299,6 +307,7 @@
|
|
|
299
307
|
"tsc-alias": "1.9.7",
|
|
300
308
|
"typescript": "7.0.2",
|
|
301
309
|
"vite": "7.3.6",
|
|
302
|
-
"xstate": "5.33.0"
|
|
310
|
+
"xstate": "5.33.0",
|
|
311
|
+
"yup": "1.7.1"
|
|
303
312
|
}
|
|
304
313
|
}
|