@stackcraftmx/calcita 0.47.0 → 0.51.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 +173 -12
- package/cli/calcita.js +15 -0
- package/cli/checkTexts.js +209 -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/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/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 +186 -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 +3 -2
- package/dist/inputs/WizardLayout.js.map +1 -1
- 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 +6 -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/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/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 +8 -1
- 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 +6 -19
- 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 +6 -31
- 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/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 +6 -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 +4 -3
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createElement, useSyncExternalStore } from "react";
|
|
3
|
-
import { hashHrefOf, hashLocationOf } from "./navigationPaths.js";
|
|
3
|
+
import { hashHrefOf, hashLocationOf, isPlainLeftClick } from "./navigationPaths.js";
|
|
4
4
|
const HISTORY_BACK = -1;
|
|
5
5
|
function subscribeToHash(onChange) {
|
|
6
6
|
window.addEventListener("hashchange", onChange);
|
|
@@ -14,13 +14,17 @@ function currentHref() {
|
|
|
14
14
|
return window.location.href;
|
|
15
15
|
}
|
|
16
16
|
function createHashNavigation() {
|
|
17
|
-
const navigate = (destination) => {
|
|
17
|
+
const navigate = (destination, options) => {
|
|
18
18
|
if (destination === HISTORY_BACK) {
|
|
19
19
|
window.history.back();
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const href = hashHrefOf(destination);
|
|
23
23
|
if (href.startsWith("#")) {
|
|
24
|
+
if (options?.replace) {
|
|
25
|
+
window.location.replace(href);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
24
28
|
window.location.hash = href;
|
|
25
29
|
return;
|
|
26
30
|
}
|
|
@@ -31,7 +35,17 @@ function createHashNavigation() {
|
|
|
31
35
|
const { pathname, search } = hashLocationOf(href ? new URL(href).hash : "");
|
|
32
36
|
return { pathname, search, key: href };
|
|
33
37
|
};
|
|
34
|
-
const HashLink = ({ to, ...props }) =>
|
|
38
|
+
const HashLink = ({ to, replace, onClick, ...props }) => {
|
|
39
|
+
const href = hashHrefOf(to);
|
|
40
|
+
const handleClick = (event) => {
|
|
41
|
+
onClick?.(event);
|
|
42
|
+
if (replace && isPlainLeftClick(event, props.target)) {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
window.location.replace(href);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return createElement("a", { href, ...props, onClick: handleClick });
|
|
48
|
+
};
|
|
35
49
|
return Object.freeze({ useNavigate: () => navigate, useLocation: useHashLocation, Link: HashLink });
|
|
36
50
|
}
|
|
37
51
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hashNavigation.js","sources":["../../src/toolkit/hashNavigation.js"],"sourcesContent":["// La navegación con # en la dirección (/app.php#/pedidos), sin router: para meter Calcita en un sistema que ya existe y cuyo\n// servidor no sabe responder /pedidos al recargar. Todo lo que va después del # se queda en el navegador: cambiar de\n// pantalla no recarga la página ni pide nada al servidor, y atrás y adelante funcionan.\n//\n// <ToolkitProvider navigation={createHashNavigation()}> // una vez, fuera del componente\n//\n// Con react-router se usa su createHashRouter con el adaptador de siempre (@stackcraftmx/calcita/react-router).\n//\n// Funciones genéricas: function (regla de la casa).\nimport {createElement, useSyncExternalStore} from 'react';\n\nimport {hashHrefOf, hashLocationOf} from '@/toolkit/navigationPaths.js';\n\nconst HISTORY_BACK = -1;\n\n/** Avisa cuando cambia lo que va después del # (un enlace, atrás o adelante). */\nfunction subscribeToHash(onChange) {\n window.addEventListener('hashchange', onChange);\n window.addEventListener('popstate', onChange);\n return () => {\n window.removeEventListener('hashchange', onChange);\n window.removeEventListener('popstate', onChange);\n };\n}\n\nfunction currentHref() {\n return window.location.href;\n}\n\n/**\n * @returns {{useNavigate: () => (destination: string|number) => void, useLocation: () => {pathname: string, search: string, key: string}, Link: import('react').ElementType}}\n */\nexport function createHashNavigation() {\n // -1 regresa en el historial; una ruta de la app cambia lo que va después del # (sin recargar)\n const navigate = (destination) => {\n if (destination === HISTORY_BACK) {\n window.history.back();\n return;\n }\n const href = hashHrefOf(destination);\n if (href.startsWith('#')) {\n window.location.hash = href;\n return;\n }\n // una dirección de afuera: como un enlace normal\n window.location.assign(href);\n };\n\n // la página de la app, leída de lo que va después del #\n const useHashLocation = () => {\n const href = useSyncExternalStore(subscribeToHash, currentHref, () => '');\n const {pathname, search} = hashLocationOf(href ? new URL(href).hash : '');\n return {pathname, search, key: href};\n };\n\n const HashLink = ({to, ...props}) => createElement('a', {href
|
|
1
|
+
{"version":3,"file":"hashNavigation.js","sources":["../../src/toolkit/hashNavigation.js"],"sourcesContent":["// La navegación con # en la dirección (/app.php#/pedidos), sin router: para meter Calcita en un sistema que ya existe y cuyo\n// servidor no sabe responder /pedidos al recargar. Todo lo que va después del # se queda en el navegador: cambiar de\n// pantalla no recarga la página ni pide nada al servidor, y atrás y adelante funcionan.\n//\n// <ToolkitProvider navigation={createHashNavigation()}> // una vez, fuera del componente\n//\n// Con react-router se usa su createHashRouter con el adaptador de siempre (@stackcraftmx/calcita/react-router).\n//\n// Funciones genéricas: function (regla de la casa).\nimport {createElement, useSyncExternalStore} from 'react';\n\nimport {hashHrefOf, hashLocationOf, isPlainLeftClick} from '@/toolkit/navigationPaths.js';\n\nconst HISTORY_BACK = -1;\n\n/** Avisa cuando cambia lo que va después del # (un enlace, atrás o adelante). */\nfunction subscribeToHash(onChange) {\n window.addEventListener('hashchange', onChange);\n window.addEventListener('popstate', onChange);\n return () => {\n window.removeEventListener('hashchange', onChange);\n window.removeEventListener('popstate', onChange);\n };\n}\n\nfunction currentHref() {\n return window.location.href;\n}\n\n/**\n * @returns {{useNavigate: () => (destination: string|number, options?: {replace?: boolean}) => void, useLocation: () => {pathname: string, search: string, key: string}, Link: import('react').ElementType}}\n */\nexport function createHashNavigation() {\n // -1 regresa en el historial; una ruta de la app cambia lo que va después del # (sin recargar). Con {replace: true}\n // toma el lugar de la actual en el historial\n const navigate = (destination, options) => {\n if (destination === HISTORY_BACK) {\n window.history.back();\n return;\n }\n const href = hashHrefOf(destination);\n if (href.startsWith('#')) {\n if (options?.replace) {\n window.location.replace(href);\n return;\n }\n window.location.hash = href;\n return;\n }\n // una dirección de afuera: como un enlace normal\n window.location.assign(href);\n };\n\n // la página de la app, leída de lo que va después del #\n const useHashLocation = () => {\n const href = useSyncExternalStore(subscribeToHash, currentHref, () => '');\n const {pathname, search} = hashLocationOf(href ? new URL(href).hash : '');\n return {pathname, search, key: href};\n };\n\n // con `replace`, el clic normal reemplaza la entrada del historial; Cmd/Ctrl+clic abre otra pestaña como siempre\n const HashLink = ({to, replace, onClick, ...props}) => {\n const href = hashHrefOf(to);\n const handleClick = (event) => {\n onClick?.(event);\n if (replace && isPlainLeftClick(event, props.target)) {\n event.preventDefault();\n window.location.replace(href);\n }\n };\n return createElement('a', {href, ...props, onClick: handleClick});\n };\n\n return Object.freeze({useNavigate: () => navigate, useLocation: useHashLocation, Link: HashLink});\n}\n"],"names":[],"mappings":";;;AAaA,MAAM,eAAe;AAGrB,SAAS,gBAAgB,UAAU;AAC/B,SAAO,iBAAiB,cAAc,QAAQ;AAC9C,SAAO,iBAAiB,YAAY,QAAQ;AAC5C,SAAO,MAAM;AACT,WAAO,oBAAoB,cAAc,QAAQ;AACjD,WAAO,oBAAoB,YAAY,QAAQ;AAAA,EACnD;AACJ;AAEA,SAAS,cAAc;AACnB,SAAO,OAAO,SAAS;AAC3B;AAKO,SAAS,uBAAuB;AAGnC,QAAM,WAAW,CAAC,aAAa,YAAY;AACvC,QAAI,gBAAgB,cAAc;AAC9B,aAAO,QAAQ,KAAI;AACnB;AAAA,IACJ;AACA,UAAM,OAAO,WAAW,WAAW;AACnC,QAAI,KAAK,WAAW,GAAG,GAAG;AACtB,UAAI,SAAS,SAAS;AAClB,eAAO,SAAS,QAAQ,IAAI;AAC5B;AAAA,MACJ;AACA,aAAO,SAAS,OAAO;AACvB;AAAA,IACJ;AAEA,WAAO,SAAS,OAAO,IAAI;AAAA,EAC/B;AAGA,QAAM,kBAAkB,MAAM;AAC1B,UAAM,OAAO,qBAAqB,iBAAiB,aAAa,MAAM,EAAE;AACxE,UAAM,EAAC,UAAU,OAAM,IAAI,eAAe,OAAO,IAAI,IAAI,IAAI,EAAE,OAAO,EAAE;AACxE,WAAO,EAAC,UAAU,QAAQ,KAAK,KAAI;AAAA,EACvC;AAGA,QAAM,WAAW,CAAC,EAAC,IAAI,SAAS,SAAS,GAAG,MAAK,MAAM;AACnD,UAAM,OAAO,WAAW,EAAE;AAC1B,UAAM,cAAc,CAAC,UAAU;AAC3B,gBAAU,KAAK;AACf,UAAI,WAAW,iBAAiB,OAAO,MAAM,MAAM,GAAG;AAClD,cAAM,eAAc;AACpB,eAAO,SAAS,QAAQ,IAAI;AAAA,MAChC;AAAA,IACJ;AACA,WAAO,cAAc,KAAK,EAAC,MAAM,GAAG,OAAO,SAAS,YAAW,CAAC;AAAA,EACpE;AAEA,SAAO,OAAO,OAAO,EAAC,aAAa,MAAM,UAAU,aAAa,iBAAiB,MAAM,SAAQ,CAAC;AACpG;"}
|
|
@@ -39,9 +39,24 @@ function hashLocationOf(hash) {
|
|
|
39
39
|
function hashHrefOf(destination) {
|
|
40
40
|
return isAppPath(destination) ? `${HASH_SIGN}${destination}` : destination;
|
|
41
41
|
}
|
|
42
|
+
const MAIN_MOUSE_BUTTON = 0;
|
|
43
|
+
function isPlainLeftClick(event, target) {
|
|
44
|
+
if (target && target !== "_self") {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return event.button === MAIN_MOUSE_BUTTON && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.defaultPrevented;
|
|
48
|
+
}
|
|
49
|
+
function documentBasePath(currentDocument = globalThis.document) {
|
|
50
|
+
if (!currentDocument?.querySelector?.("base[href]") || !currentDocument.baseURI) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return normalizedBasePath(new URL(currentDocument.baseURI).pathname);
|
|
54
|
+
}
|
|
42
55
|
export {
|
|
56
|
+
documentBasePath,
|
|
43
57
|
hashHrefOf,
|
|
44
58
|
hashLocationOf,
|
|
59
|
+
isPlainLeftClick,
|
|
45
60
|
normalizedBasePath,
|
|
46
61
|
pathWithBase,
|
|
47
62
|
pathWithoutBase
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigationPaths.js","sources":["../../src/toolkit/navigationPaths.js"],"sourcesContent":["// Las rutas de la navegación sin router, para sistemas que ya existen (una página de PHP, JSP o .NET con React en un pedazo):\n// - con prefijo: la app vive en /portal/… detrás de un proxy, y los componentes hablan de /pedidos sin saberlo;\n// - con # en la dirección (/app.php#/pedidos): el servidor viejo no sabe responder /pedidos al recargar, y todo lo que va\n// después del # se queda en el navegador.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\n\nconst HASH_SIGN = '#';\nconst ROOT_PATH = '/';\n\n/**\n * El prefijo limpio: '' sin prefijo; si no, empieza con / y no termina con / ('portal/' → '/portal').\n *\n * @param {string|null|undefined} basePath\n * @returns {string}\n */\nexport function normalizedBasePath(basePath) {\n const trimmed = (basePath ?? '').trim().replace(/\\/+$/, '');\n if (!trimmed) {\n return '';\n }\n return trimmed.startsWith(ROOT_PATH) ? trimmed : `${ROOT_PATH}${trimmed}`;\n}\n\n/**\n * ¿Es una ruta de la app ('/pedidos')? Una dirección de afuera ('https://…', '//otro.sitio') o relativa ('?pagina=2') no.\n *\n * @param {string} destination\n * @returns {boolean}\n */\nfunction isAppPath(destination) {\n return destination.startsWith(ROOT_PATH) && !destination.startsWith('//');\n}\n\n/**\n * La dirección real de una ruta de la app con el prefijo puesto: '/pedidos' → '/portal/pedidos'. Lo que no es ruta de la\n * app se queda como viene.\n *\n * @param {string} basePath\n * @param {string} destination\n * @returns {string}\n */\nexport function pathWithBase(basePath, destination) {\n const base = normalizedBasePath(basePath);\n return base && isAppPath(destination) ? `${base}${destination}` : destination;\n}\n\n/**\n * La ruta de la app de una dirección real, sin el prefijo: '/portal/pedidos' → '/pedidos'; el prefijo solo → '/'. Una\n * dirección de fuera del prefijo se queda como viene.\n *\n * @param {string} basePath\n * @param {string} pathname\n * @returns {string}\n */\nexport function pathWithoutBase(basePath, pathname) {\n const base = normalizedBasePath(basePath);\n if (!base) {\n return pathname;\n }\n if (pathname === base) {\n return ROOT_PATH;\n }\n return pathname.startsWith(`${base}${ROOT_PATH}`) ? pathname.slice(base.length) : pathname;\n}\n\n/**\n * La página de la app que va después del # ('#/pedidos?estado=pendiente' → {pathname: '/pedidos', search: '?estado=pendiente'}).\n * Sin nada después del #, el inicio.\n *\n * @param {string} hash el de la dirección (location.hash), con o sin #\n * @returns {{pathname: string, search: string}}\n */\nexport function hashLocationOf(hash) {\n const route = (hash ?? '').replace(/^#/, '');\n if (!route) {\n return {pathname: ROOT_PATH, search: ''};\n }\n const searchStart = route.indexOf('?');\n const pathname = searchStart === -1 ? route : route.slice(0, searchStart);\n return {\n pathname: pathname.startsWith(ROOT_PATH) ? pathname : `${ROOT_PATH}${pathname}`,\n search: searchStart === -1 ? '' : route.slice(searchStart),\n };\n}\n\n/**\n * El enlace de una ruta de la app con # ('/pedidos' → '#/pedidos'). Lo que no es ruta de la app se queda como viene.\n *\n * @param {string} destination\n * @returns {string}\n */\nexport function hashHrefOf(destination) {\n return isAppPath(destination) ? `${HASH_SIGN}${destination}` : destination;\n}\n"],"names":[],"mappings":"AAOA,MAAM,YAAY;AAClB,MAAM,YAAY;AAQX,SAAS,mBAAmB,UAAU;AACzC,QAAM,WAAW,YAAY,IAAI,KAAI,EAAG,QAAQ,QAAQ,EAAE;AAC1D,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,SAAO,QAAQ,WAAW,SAAS,IAAI,UAAU,GAAG,SAAS,GAAG,OAAO;AAC3E;AAQA,SAAS,UAAU,aAAa;AAC5B,SAAO,YAAY,WAAW,SAAS,KAAK,CAAC,YAAY,WAAW,IAAI;AAC5E;AAUO,SAAS,aAAa,UAAU,aAAa;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,SAAO,QAAQ,UAAU,WAAW,IAAI,GAAG,IAAI,GAAG,WAAW,KAAK;AACtE;AAUO,SAAS,gBAAgB,UAAU,UAAU;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AACA,MAAI,aAAa,MAAM;AACnB,WAAO;AAAA,EACX;AACA,SAAO,SAAS,WAAW,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,SAAS,MAAM,KAAK,MAAM,IAAI;AACtF;AASO,SAAS,eAAe,MAAM;AACjC,QAAM,SAAS,QAAQ,IAAI,QAAQ,MAAM,EAAE;AAC3C,MAAI,CAAC,OAAO;AACR,WAAO,EAAC,UAAU,WAAW,QAAQ,GAAE;AAAA,EAC3C;AACA,QAAM,cAAc,MAAM,QAAQ,GAAG;AACrC,QAAM,WAAW,gBAAgB,KAAK,QAAQ,MAAM,MAAM,GAAG,WAAW;AACxE,SAAO;AAAA,IACH,UAAU,SAAS,WAAW,SAAS,IAAI,WAAW,GAAG,SAAS,GAAG,QAAQ;AAAA,IAC7E,QAAQ,gBAAgB,KAAK,KAAK,MAAM,MAAM,WAAW;AAAA,EACjE;AACA;AAQO,SAAS,WAAW,aAAa;AACpC,SAAO,UAAU,WAAW,IAAI,GAAG,SAAS,GAAG,WAAW,KAAK;AACnE;"}
|
|
1
|
+
{"version":3,"file":"navigationPaths.js","sources":["../../src/toolkit/navigationPaths.js"],"sourcesContent":["// Las rutas de la navegación sin router, para sistemas que ya existen (una página de PHP, JSP o .NET con React en un pedazo):\n// - con prefijo: la app vive en /portal/… detrás de un proxy, y los componentes hablan de /pedidos sin saberlo;\n// - con # en la dirección (/app.php#/pedidos): el servidor viejo no sabe responder /pedidos al recargar, y todo lo que va\n// después del # se queda en el navegador.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\n\nconst HASH_SIGN = '#';\nconst ROOT_PATH = '/';\n\n/**\n * El prefijo limpio: '' sin prefijo; si no, empieza con / y no termina con / ('portal/' → '/portal').\n *\n * @param {string|null|undefined} basePath\n * @returns {string}\n */\nexport function normalizedBasePath(basePath) {\n const trimmed = (basePath ?? '').trim().replace(/\\/+$/, '');\n if (!trimmed) {\n return '';\n }\n return trimmed.startsWith(ROOT_PATH) ? trimmed : `${ROOT_PATH}${trimmed}`;\n}\n\n/**\n * ¿Es una ruta de la app ('/pedidos')? Una dirección de afuera ('https://…', '//otro.sitio') o relativa ('?pagina=2') no.\n *\n * @param {string} destination\n * @returns {boolean}\n */\nfunction isAppPath(destination) {\n return destination.startsWith(ROOT_PATH) && !destination.startsWith('//');\n}\n\n/**\n * La dirección real de una ruta de la app con el prefijo puesto: '/pedidos' → '/portal/pedidos'. Lo que no es ruta de la\n * app se queda como viene.\n *\n * @param {string} basePath\n * @param {string} destination\n * @returns {string}\n */\nexport function pathWithBase(basePath, destination) {\n const base = normalizedBasePath(basePath);\n return base && isAppPath(destination) ? `${base}${destination}` : destination;\n}\n\n/**\n * La ruta de la app de una dirección real, sin el prefijo: '/portal/pedidos' → '/pedidos'; el prefijo solo → '/'. Una\n * dirección de fuera del prefijo se queda como viene.\n *\n * @param {string} basePath\n * @param {string} pathname\n * @returns {string}\n */\nexport function pathWithoutBase(basePath, pathname) {\n const base = normalizedBasePath(basePath);\n if (!base) {\n return pathname;\n }\n if (pathname === base) {\n return ROOT_PATH;\n }\n return pathname.startsWith(`${base}${ROOT_PATH}`) ? pathname.slice(base.length) : pathname;\n}\n\n/**\n * La página de la app que va después del # ('#/pedidos?estado=pendiente' → {pathname: '/pedidos', search: '?estado=pendiente'}).\n * Sin nada después del #, el inicio.\n *\n * @param {string} hash el de la dirección (location.hash), con o sin #\n * @returns {{pathname: string, search: string}}\n */\nexport function hashLocationOf(hash) {\n const route = (hash ?? '').replace(/^#/, '');\n if (!route) {\n return {pathname: ROOT_PATH, search: ''};\n }\n const searchStart = route.indexOf('?');\n const pathname = searchStart === -1 ? route : route.slice(0, searchStart);\n return {\n pathname: pathname.startsWith(ROOT_PATH) ? pathname : `${ROOT_PATH}${pathname}`,\n search: searchStart === -1 ? '' : route.slice(searchStart),\n };\n}\n\n/**\n * El enlace de una ruta de la app con # ('/pedidos' → '#/pedidos'). Lo que no es ruta de la app se queda como viene.\n *\n * @param {string} destination\n * @returns {string}\n */\nexport function hashHrefOf(destination) {\n return isAppPath(destination) ? `${HASH_SIGN}${destination}` : destination;\n}\n\n// el botón principal del ratón (el izquierdo)\nconst MAIN_MOUSE_BUTTON = 0;\n\n/**\n * Si un clic en un enlace es el normal: el botón principal, sin Cmd/Ctrl/Shift/Alt y sin que nadie lo haya detenido.\n * Solo ese se hace por dentro (cambiar de pantalla, reemplazar el historial); con Cmd/Ctrl+clic, Shift+clic o el botón de en\n * medio el navegador hace lo suyo (otra pestaña, otra ventana), como con cualquier liga.\n *\n * @param {{button?: number, metaKey?: boolean, ctrlKey?: boolean, shiftKey?: boolean, altKey?: boolean, defaultPrevented?: boolean}} event\n * @param {string} [target] el target del enlace: con _blank tampoco se hace por dentro\n * @returns {boolean}\n */\nexport function isPlainLeftClick(event, target) {\n if (target && target !== '_self') {\n return false;\n }\n return event.button === MAIN_MOUSE_BUTTON && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.defaultPrevented;\n}\n\n/**\n * El prefijo con que el servidor sirvió la página, leído al abrirla de su <base href> ('/ventas'), o null si la página no\n * trae <base>. Así UNA compilación sirve detrás de cualquier prefijo que decida el servidor (Laravel lo pone con\n * config('app.url'), un proxy con su ruta): el prefijo no se fija al compilar. Para el basename del router y para\n * createBrowserNavigation({basePath}).\n *\n * <base href=\"{{ rtrim(config('app.url'), '/') . '/' }}\"> (en la vista que sirve la app)\n * createBrowserRouter(routes, {basename: documentBasePath() || '/'})\n *\n * OJO: con <base>, todo lo relativo de la página (imágenes, ligas «#sección») se lee desde ese prefijo.\n *\n * @param {{baseURI?: string, querySelector?: (selector: string) => unknown}} [currentDocument] por omisión el de la página\n * @returns {string|null} '' en la raíz; null sin <base> (o sin navegador)\n */\nexport function documentBasePath(currentDocument = globalThis.document) {\n if (!currentDocument?.querySelector?.('base[href]') || !currentDocument.baseURI) {\n return null;\n }\n return normalizedBasePath(new URL(currentDocument.baseURI).pathname);\n}\n"],"names":[],"mappings":"AAOA,MAAM,YAAY;AAClB,MAAM,YAAY;AAQX,SAAS,mBAAmB,UAAU;AACzC,QAAM,WAAW,YAAY,IAAI,KAAI,EAAG,QAAQ,QAAQ,EAAE;AAC1D,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,SAAO,QAAQ,WAAW,SAAS,IAAI,UAAU,GAAG,SAAS,GAAG,OAAO;AAC3E;AAQA,SAAS,UAAU,aAAa;AAC5B,SAAO,YAAY,WAAW,SAAS,KAAK,CAAC,YAAY,WAAW,IAAI;AAC5E;AAUO,SAAS,aAAa,UAAU,aAAa;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,SAAO,QAAQ,UAAU,WAAW,IAAI,GAAG,IAAI,GAAG,WAAW,KAAK;AACtE;AAUO,SAAS,gBAAgB,UAAU,UAAU;AAChD,QAAM,OAAO,mBAAmB,QAAQ;AACxC,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AACA,MAAI,aAAa,MAAM;AACnB,WAAO;AAAA,EACX;AACA,SAAO,SAAS,WAAW,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,SAAS,MAAM,KAAK,MAAM,IAAI;AACtF;AASO,SAAS,eAAe,MAAM;AACjC,QAAM,SAAS,QAAQ,IAAI,QAAQ,MAAM,EAAE;AAC3C,MAAI,CAAC,OAAO;AACR,WAAO,EAAC,UAAU,WAAW,QAAQ,GAAE;AAAA,EAC3C;AACA,QAAM,cAAc,MAAM,QAAQ,GAAG;AACrC,QAAM,WAAW,gBAAgB,KAAK,QAAQ,MAAM,MAAM,GAAG,WAAW;AACxE,SAAO;AAAA,IACH,UAAU,SAAS,WAAW,SAAS,IAAI,WAAW,GAAG,SAAS,GAAG,QAAQ;AAAA,IAC7E,QAAQ,gBAAgB,KAAK,KAAK,MAAM,MAAM,WAAW;AAAA,EACjE;AACA;AAQO,SAAS,WAAW,aAAa;AACpC,SAAO,UAAU,WAAW,IAAI,GAAG,SAAS,GAAG,WAAW,KAAK;AACnE;AAGA,MAAM,oBAAoB;AAWnB,SAAS,iBAAiB,OAAO,QAAQ;AAC5C,MAAI,UAAU,WAAW,SAAS;AAC9B,WAAO;AAAA,EACX;AACA,SAAO,MAAM,WAAW,qBAAqB,CAAC,MAAM,WAAW,CAAC,MAAM,WAAW,CAAC,MAAM,YAAY,CAAC,MAAM,UAAU,CAAC,MAAM;AAChI;AAgBO,SAAS,iBAAiB,kBAAkB,WAAW,UAAU;AACpE,MAAI,CAAC,iBAAiB,gBAAgB,YAAY,KAAK,CAAC,gBAAgB,SAAS;AAC7E,WAAO;AAAA,EACX;AACA,SAAO,mBAAmB,IAAI,IAAI,gBAAgB,OAAO,EAAE,QAAQ;AACvE;"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const SEPARATOR = ":";
|
|
2
|
+
const DEFAULT_MODULE_PATTERN = /(?:^|\/)modules\/(.+)\/[^/]+$/;
|
|
3
|
+
function fillPath(route, params = {}, name = route) {
|
|
4
|
+
const used = /* @__PURE__ */ new Set();
|
|
5
|
+
const filled = route.replace(/:([A-Za-z0-9_]+)\??/g, (whole, part) => {
|
|
6
|
+
const value = params[part];
|
|
7
|
+
if (value === void 0 || value === null || value === "") {
|
|
8
|
+
if (whole.endsWith("?")) {
|
|
9
|
+
used.add(part);
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`La dirección «${name}» necesita ${part}. Se le dio: ${Object.keys(params).join(", ") || "nada"}`);
|
|
13
|
+
}
|
|
14
|
+
used.add(part);
|
|
15
|
+
return encodeURIComponent(String(value));
|
|
16
|
+
}).replace(/([^:])\/{2,}/g, "$1/").replace(/(.)\/+$/, "$1");
|
|
17
|
+
const query = new URLSearchParams(
|
|
18
|
+
Object.entries(params).filter(([key, value]) => !used.has(key) && value !== void 0 && value !== null && value !== "").map(([key, value]) => [key, String(value)])
|
|
19
|
+
);
|
|
20
|
+
return query.size > 0 ? `${filled}?${query}` : filled;
|
|
21
|
+
}
|
|
22
|
+
function placeInTree(tree, steps, value) {
|
|
23
|
+
let current = tree;
|
|
24
|
+
for (const step of steps.slice(0, -1)) {
|
|
25
|
+
current[step] = current[step] ?? {};
|
|
26
|
+
current = current[step];
|
|
27
|
+
}
|
|
28
|
+
const last = steps[steps.length - 1];
|
|
29
|
+
current[last] = { ...current[last] ?? {}, ...value };
|
|
30
|
+
}
|
|
31
|
+
function createPathIndex(modules, { exportName = "paths", modulePattern = DEFAULT_MODULE_PATTERN } = {}) {
|
|
32
|
+
const tree = {};
|
|
33
|
+
for (const [file, moduleExports] of Object.entries(modules)) {
|
|
34
|
+
const published = moduleExports?.[exportName];
|
|
35
|
+
if (!published) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const match = modulePattern.exec(file);
|
|
39
|
+
if (!match) {
|
|
40
|
+
throw new Error(`No sé de qué módulo es «${file}»: el archivo va dentro de modules/<módulo>/`);
|
|
41
|
+
}
|
|
42
|
+
placeInTree(tree, match[1].split("/"), published);
|
|
43
|
+
}
|
|
44
|
+
const pathOf = (name, params = {}) => {
|
|
45
|
+
let current = tree;
|
|
46
|
+
const walked = [];
|
|
47
|
+
for (const step of name.split(SEPARATOR)) {
|
|
48
|
+
if (current === null || typeof current !== "object" || current[step] === void 0) {
|
|
49
|
+
const options = current && typeof current === "object" ? Object.keys(current).join(", ") : "(nada)";
|
|
50
|
+
throw new Error(`No hay una dirección llamada «${name}». En ${walked.join(SEPARATOR) || "el índice"} hay: ${options}`);
|
|
51
|
+
}
|
|
52
|
+
current = current[step];
|
|
53
|
+
walked.push(step);
|
|
54
|
+
}
|
|
55
|
+
if (typeof current !== "string") {
|
|
56
|
+
throw new Error(`«${name}» no es una dirección sino un grupo. Dentro hay: ${Object.keys(current).join(", ")}`);
|
|
57
|
+
}
|
|
58
|
+
return fillPath(current, params, name);
|
|
59
|
+
};
|
|
60
|
+
return Object.freeze({ pathOf, allPaths: () => tree });
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
createPathIndex,
|
|
64
|
+
fillPath
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=pathIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathIndex.js","sources":["../../src/toolkit/pathIndex.js"],"sourcesContent":["// El índice de direcciones con nombre: cada módulo publica las suyas en su archivo (paths.js de las pantallas, uris.js de\n// las del API) y el índice las junta, buscables por camino con dos puntos: pathOf('admin:clients:providerList').\n//\n// Por qué: cuando una pantalla tiene que llevar a la de OTRO módulo (el detalle de un cliente regresa a la lista de donde\n// salió), sin el índice un módulo importaría al otro y dejarían de ser independientes (se borra uno y el otro no compila).\n// No es una lista central que todos editan: el dueño de la pantalla es el dueño de su dirección y el índice se arma solo.\n//\n// // src/app/appPaths.js — el glob tiene que ser un texto literal: Vite lo resuelve al compilar\n// export const {pathOf, allPaths} = createPathIndex(import.meta.glob('@/modules/**/paths.js', {eager: true}));\n//\n// pathOf('admin:profile:detail', {groupId: 2, userId: 7675}) → '/admin/user/detail/2/7675'\n// pathOf('admin:profile:detail', {groupId: 2, userId: 7675, tab: 'docs'}) → '/admin/user/detail/2/7675?tab=docs'\n//\n// Lo que la ruta pide con dos puntos (:groupId) se sustituye; lo que sobra se va como consulta. Si el nombre no existe o falta\n// una parte, TRUENA y dice qué sí hay: un `undefined` en una dirección manda a la persona a otra pantalla sin decir por qué\n// (o a un 404 raro del API a los diez minutos de buscar).\n//\n// Lo mismo sirve para las direcciones del API (uris.js con export const uris = {...}): createPathIndex(glob, {exportName: 'uris'}).\n//\n// Funciones puras, no renderizan: function (regla de la casa). Pruebas en pathIndex.test.js.\n\nconst SEPARATOR = ':';\n// el camino de un módulo sale de su carpeta: …/modules/admin/clients/paths.js → ['admin', 'clients']\nconst DEFAULT_MODULE_PATTERN = /(?:^|\\/)modules\\/(.+)\\/[^/]+$/;\n\n/**\n * Le pone sus partes a una ruta: las que pide con dos puntos y, lo que sobre, la consulta. Los nulos y los vacíos no se\n * escriben.\n *\n * @param {string} route la ruta con sus :partes ('/orders/:orderId', ':page?' es opcional)\n * @param {Record<string, unknown>} [params]\n * @param {string} [name] cómo se llama, para decirlo si algo falta\n * @returns {string}\n * @throws {Error} si la ruta pide una parte obligatoria que no viene\n */\nexport function fillPath(route, params = {}, name = route) {\n const used = new Set();\n const filled = route.replace(/:([A-Za-z0-9_]+)\\??/g, (whole, part) => {\n const value = params[part];\n if (value === undefined || value === null || value === '') {\n // la parte opcional (:page?) puede faltar; la obligatoria, no\n if (whole.endsWith('?')) {\n used.add(part);\n return '';\n }\n throw new Error(`La dirección «${name}» necesita ${part}. Se le dio: ${Object.keys(params).join(', ') || 'nada'}`);\n }\n used.add(part);\n return encodeURIComponent(String(value));\n // la parte opcional que faltó deja «//» o una diagonal al final; «https://» se respeta\n }).replace(/([^:])\\/{2,}/g, '$1/').replace(/(.)\\/+$/, '$1');\n\n // lo que sobra es la consulta: así una liga abre una pestaña (?tab=docs) o una lista ya filtrada\n const query = new URLSearchParams(\n Object.entries(params)\n .filter(([key, value]) => !used.has(key) && value !== undefined && value !== null && value !== '')\n .map(([key, value]) => [key, String(value)]),\n );\n return query.size > 0 ? `${filled}?${query}` : filled;\n}\n\n/**\n * Mete lo de un módulo en el árbol, un tramo por nivel (admin/clients → {admin: {clients: …}}): el buscador baja nivel por\n * nivel, así que el árbol va anidado igual que se busca.\n */\nfunction placeInTree(tree, steps, value) {\n let current = tree;\n for (const step of steps.slice(0, -1)) {\n current[step] = current[step] ?? {};\n current = current[step];\n }\n const last = steps[steps.length - 1];\n current[last] = {...(current[last] ?? {}), ...value};\n}\n\n/**\n * El índice de las direcciones que publica cada módulo.\n *\n * @param {Record<string, Record<string, unknown>>} modules lo que da import.meta.glob(..., {eager: true}): archivo → sus exports\n * @param {object} [options]\n * @param {string} [options.exportName] el export con las direcciones en cada archivo (por omisión 'paths'; para el API, 'uris')\n * @param {RegExp} [options.modulePattern] saca del nombre del archivo el camino del módulo (el primer grupo, con /)\n * @returns {{pathOf: (name: string, params?: Record<string, unknown>) => string, allPaths: () => object}}\n */\nexport function createPathIndex(modules, {exportName = 'paths', modulePattern = DEFAULT_MODULE_PATTERN} = {}) {\n const tree = {};\n for (const [file, moduleExports] of Object.entries(modules)) {\n const published = moduleExports?.[exportName];\n // un archivo que no publica nada no entra al árbol\n if (!published) {\n continue;\n }\n const match = modulePattern.exec(file);\n if (!match) {\n throw new Error(`No sé de qué módulo es «${file}»: el archivo va dentro de modules/<módulo>/`);\n }\n placeInTree(tree, match[1].split('/'), published);\n }\n\n const pathOf = (name, params = {}) => {\n let current = tree;\n const walked = [];\n for (const step of name.split(SEPARATOR)) {\n if (current === null || typeof current !== 'object' || current[step] === undefined) {\n const options = current && typeof current === 'object' ? Object.keys(current).join(', ') : '(nada)';\n throw new Error(`No hay una dirección llamada «${name}». En ${walked.join(SEPARATOR) || 'el índice'} hay: ${options}`);\n }\n current = current[step];\n walked.push(step);\n }\n // quedarse a media rama da un grupo, no una dirección\n if (typeof current !== 'string') {\n throw new Error(`«${name}» no es una dirección sino un grupo. Dentro hay: ${Object.keys(current).join(', ')}`);\n }\n return fillPath(current, params, name);\n };\n\n return Object.freeze({pathOf, allPaths: () => tree});\n}\n"],"names":[],"mappings":"AAqBA,MAAM,YAAY;AAElB,MAAM,yBAAyB;AAYxB,SAAS,SAAS,OAAO,SAAS,CAAA,GAAI,OAAO,OAAO;AACvD,QAAM,OAAO,oBAAI,IAAG;AACpB,QAAM,SAAS,MAAM,QAAQ,wBAAwB,CAAC,OAAO,SAAS;AAClE,UAAM,QAAQ,OAAO,IAAI;AACzB,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AAEvD,UAAI,MAAM,SAAS,GAAG,GAAG;AACrB,aAAK,IAAI,IAAI;AACb,eAAO;AAAA,MACX;AACA,YAAM,IAAI,MAAM,iBAAiB,IAAI,cAAc,IAAI,gBAAgB,OAAO,KAAK,MAAM,EAAE,KAAK,IAAI,KAAK,MAAM,EAAE;AAAA,IACrH;AACA,SAAK,IAAI,IAAI;AACb,WAAO,mBAAmB,OAAO,KAAK,CAAC;AAAA,EAE3C,CAAC,EAAE,QAAQ,iBAAiB,KAAK,EAAE,QAAQ,WAAW,IAAI;AAG1D,QAAM,QAAQ,IAAI;AAAA,IACd,OAAO,QAAQ,MAAM,EAChB,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,IAAI,GAAG,KAAK,UAAU,UAAa,UAAU,QAAQ,UAAU,EAAE,EAChG,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,OAAO,KAAK,CAAC,CAAC;AAAA,EACvD;AACI,SAAO,MAAM,OAAO,IAAI,GAAG,MAAM,IAAI,KAAK,KAAK;AACnD;AAMA,SAAS,YAAY,MAAM,OAAO,OAAO;AACrC,MAAI,UAAU;AACd,aAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACnC,YAAQ,IAAI,IAAI,QAAQ,IAAI,KAAK,CAAA;AACjC,cAAU,QAAQ,IAAI;AAAA,EAC1B;AACA,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,UAAQ,IAAI,IAAI,EAAC,GAAI,QAAQ,IAAI,KAAK,CAAA,GAAK,GAAG,MAAK;AACvD;AAWO,SAAS,gBAAgB,SAAS,EAAC,aAAa,SAAS,gBAAgB,uBAAsB,IAAI,IAAI;AAC1G,QAAM,OAAO,CAAA;AACb,aAAW,CAAC,MAAM,aAAa,KAAK,OAAO,QAAQ,OAAO,GAAG;AACzD,UAAM,YAAY,gBAAgB,UAAU;AAE5C,QAAI,CAAC,WAAW;AACZ;AAAA,IACJ;AACA,UAAM,QAAQ,cAAc,KAAK,IAAI;AACrC,QAAI,CAAC,OAAO;AACR,YAAM,IAAI,MAAM,2BAA2B,IAAI,8CAA8C;AAAA,IACjG;AACA,gBAAY,MAAM,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,SAAS;AAAA,EACpD;AAEA,QAAM,SAAS,CAAC,MAAM,SAAS,CAAA,MAAO;AAClC,QAAI,UAAU;AACd,UAAM,SAAS,CAAA;AACf,eAAW,QAAQ,KAAK,MAAM,SAAS,GAAG;AACtC,UAAI,YAAY,QAAQ,OAAO,YAAY,YAAY,QAAQ,IAAI,MAAM,QAAW;AAChF,cAAM,UAAU,WAAW,OAAO,YAAY,WAAW,OAAO,KAAK,OAAO,EAAE,KAAK,IAAI,IAAI;AAC3F,cAAM,IAAI,MAAM,iCAAiC,IAAI,SAAS,OAAO,KAAK,SAAS,KAAK,WAAW,SAAS,OAAO,EAAE;AAAA,MACzH;AACA,gBAAU,QAAQ,IAAI;AACtB,aAAO,KAAK,IAAI;AAAA,IACpB;AAEA,QAAI,OAAO,YAAY,UAAU;AAC7B,YAAM,IAAI,MAAM,IAAI,IAAI,oDAAoD,OAAO,KAAK,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,IACjH;AACA,WAAO,SAAS,SAAS,QAAQ,IAAI;AAAA,EACzC;AAEA,SAAO,OAAO,OAAO,EAAC,QAAQ,UAAU,MAAM,KAAI,CAAC;AACvD;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLogger } from "../observability/logger.js";
|
|
1
2
|
import es from "../locales/es.js";
|
|
2
3
|
import en from "../locales/en.js";
|
|
3
4
|
const DEFAULT_LANGUAGE = "es";
|
|
@@ -32,7 +33,9 @@ let currentSettings = Object.freeze({
|
|
|
32
33
|
// la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva
|
|
33
34
|
buildId: "",
|
|
34
35
|
// los idiomas que ofrece la app (DEFAULT_LANGUAGES)
|
|
35
|
-
languages: DEFAULT_LANGUAGES
|
|
36
|
+
languages: DEFAULT_LANGUAGES,
|
|
37
|
+
// a quién avisarle de un texto que no existe (reportMissingText); sin él, un aviso en la consola
|
|
38
|
+
onMissingText: null
|
|
36
39
|
});
|
|
37
40
|
function configureToolkit(settings) {
|
|
38
41
|
currentSettings = Object.freeze({ ...currentSettings, ...settings });
|
|
@@ -94,8 +97,23 @@ function translateWith(settings, defaultNamespace, key, values) {
|
|
|
94
97
|
if (typeof values?.defaultValue === "string") {
|
|
95
98
|
return interpolate(values.defaultValue, values);
|
|
96
99
|
}
|
|
100
|
+
reportMissingText(settings, namespace, plainKey);
|
|
97
101
|
return `${namespace}${NAMESPACE_SEPARATOR}${plainKey}`;
|
|
98
102
|
}
|
|
103
|
+
const log = createLogger("texts");
|
|
104
|
+
const warnedMissingTexts = /* @__PURE__ */ new Set();
|
|
105
|
+
function reportMissingText(settings, namespace, key) {
|
|
106
|
+
if (settings.onMissingText) {
|
|
107
|
+
settings.onMissingText({ namespace, key, language: settings.language });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const missingId = `${settings.language}${NAMESPACE_SEPARATOR}${namespace}${NAMESPACE_SEPARATOR}${key}`;
|
|
111
|
+
if (warnedMissingTexts.has(missingId)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
warnedMissingTexts.add(missingId);
|
|
115
|
+
log.warn(`No hay texto para «${namespace}${NAMESPACE_SEPARATOR}${key}» en «${settings.language}»: la pantalla enseña la llave`);
|
|
116
|
+
}
|
|
99
117
|
function translateToolkit(defaultNamespace, key, values) {
|
|
100
118
|
return translateWith(currentSettings, defaultNamespace, key, values);
|
|
101
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolkitSettings.js","sources":["../../src/toolkit/toolkitSettings.js"],"sourcesContent":["// La configuración del paquete: idioma, textos, zona horaria, moneda, nombre de la aplicación y navegación.\n//\n// La pone ToolkitProvider en cada render y la leen también las funciones que no son componentes (formatos de fecha y\n// número, avisos, errores del servidor). Sin proveedor valen los de omisión: español, la zona del navegador y la\n// navegación del navegador.\n//\n// Los textos se resuelven en este orden, para que cada proyecto cambie solo lo que necesite:\n// 1. translate del proyecto (por ejemplo el t de i18next), si regresa un texto;\n// 2. los textos que el proyecto pasó en `texts`, del idioma activo;\n// 3. los textos del paquete (locales/), del idioma activo y, si no está, en español.\n// Las llaves usan la forma de i18next: «namespace:llave.anidada», {{variable}} y plurales con _one / _other.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport es from '@/locales/es.js';\nimport en from '@/locales/en.js';\n\nexport const DEFAULT_LANGUAGE = 'es';\n// la moneda de los montos (código ISO 4217) cuando el proyecto no dice otra\nexport const DEFAULT_CURRENCY = 'MXN';\n\n/**\n * Cómo se escribe la hora: de 24 horas («15:10», la de omisión) o de 12 con a.m. y p.m. («3:10 p.m.»). Son los valores de\n * `hourCycle` de Intl, por eso se ven así.\n */\nexport const HOUR_CYCLE = Object.freeze({\n twentyFourHours: 'h23',\n twelveHours: 'h12',\n});\nexport const DEFAULT_HOUR_CYCLE = HOUR_CYCLE.twentyFourHours;\n\nconst PACKAGE_TEXTS_BY_LANGUAGE = Object.freeze({es, en});\n\n/**\n * Los idiomas que ofrece la app cuando el proyecto no dice otros: su código, su nombre en su propio idioma (así lo busca quien\n * lo habla) y cómo se escriben sus números y fechas (Intl). El proyecto agrega los suyos en ToolkitProvider `languages` y pone\n * sus traducciones en `texts` (lo que no traduzca sale en español); los textos del paquete solo vienen en español e inglés.\n */\nexport const DEFAULT_LANGUAGES = Object.freeze([\n Object.freeze({code: 'es', label: 'Español', locale: 'es-MX'}),\n Object.freeze({code: 'en', label: 'English', locale: 'en-US'}),\n]);\n\nconst NAMESPACE_SEPARATOR = ':';\nconst KEY_SEPARATOR = '.';\nconst PLURAL_SEPARATOR = '_';\nconst PLURAL_OTHER = 'other';\nconst INTERPOLATION = /\\{\\{\\s*(\\w+)\\s*\\}\\}/g;\n\n/**\n * La zona horaria del navegador; si el navegador no la sabe, la de la Ciudad de México.\n *\n * @returns {string}\n */\nexport function browserTimeZone() {\n return Intl.DateTimeFormat().resolvedOptions().timeZone ?? 'America/Mexico_City';\n}\n\nlet currentSettings = Object.freeze({\n language: DEFAULT_LANGUAGE,\n texts: {},\n translate: null,\n timeZone: browserTimeZone(),\n currency: DEFAULT_CURRENCY,\n // la hora de 24 o de 12 horas (HOUR_CYCLE)\n hourCycle: DEFAULT_HOUR_CYCLE,\n appName: '',\n // la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva\n buildId: '',\n // los idiomas que ofrece la app (DEFAULT_LANGUAGES)\n languages: DEFAULT_LANGUAGES,\n});\n\n/**\n * Cambia la configuración que leen las funciones del paquete. La llama ToolkitProvider; un proyecto sin React (o una\n * prueba) la puede llamar directo.\n *\n * @param {{language?: string, texts?: object, translate?: Function|null, timeZone?: string, currency?: string, hourCycle?: 'h23'|'h12', appName?: string, buildId?: string, languages?: Array<{code: string, label: string, locale?: string}>}} settings\n * @returns {void}\n */\nexport function configureToolkit(settings) {\n currentSettings = Object.freeze({...currentSettings, ...settings});\n}\n\n/**\n * La configuración vigente.\n *\n * @returns {{language: string, texts: object, translate: Function|null, timeZone: string, currency: string, hourCycle: 'h23'|'h12', appName: string, buildId: string, languages: Array<{code: string, label: string, locale?: string}>}}\n */\nexport function toolkitSettings() {\n return currentSettings;\n}\n\n/**\n * El locale de Intl del idioma: el que dice su lista de idiomas (es → es-MX, pt → pt-BR) o, si no dice, el código mismo\n * (Intl entiende «pt»). OJO: antes un idioma que no fuera es ni en salía con los números y las fechas de México.\n *\n * @param {string} language\n * @param {Array<{code: string, locale?: string}>} [languages] por omisión los de la configuración vigente\n * @returns {string}\n */\nexport function intlLocaleOf(language, languages = currentSettings.languages) {\n const known = languages?.find((entry) => entry.code === language) ?? DEFAULT_LANGUAGES.find((entry) => entry.code === language);\n return known?.locale ?? language ?? DEFAULT_LANGUAGES[0].locale;\n}\n\n/**\n * Lo que hay en una ruta de llaves («toast.error») dentro de un objeto de textos.\n *\n * @param {object|undefined} texts\n * @param {string} path\n * @returns {unknown}\n */\nfunction valueAtPath(texts, path) {\n let value = texts;\n for (const part of path.split(KEY_SEPARATOR)) {\n if (value === null || typeof value !== 'object') {\n return undefined;\n }\n value = value[part];\n }\n\n return value;\n}\n\n/**\n * El texto de una llave en un objeto de textos, con su plural si trae count (como i18next: llave_one, llave_other).\n *\n * @param {object|undefined} texts los textos de un idioma, por namespace\n * @param {string} namespace\n * @param {string} key\n * @param {object|undefined} values\n * @param {string} language\n * @returns {string|undefined}\n */\nfunction textOf(texts, namespace, key, values, language) {\n const namespaceTexts = texts?.[namespace];\n if (typeof values?.count === 'number') {\n const pluralCategory = new Intl.PluralRules(intlLocaleOf(language)).select(values.count);\n const pluralText = valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${pluralCategory}`)\n ?? valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${PLURAL_OTHER}`);\n if (typeof pluralText === 'string') {\n return pluralText;\n }\n }\n\n const text = valueAtPath(namespaceTexts, key);\n\n return typeof text === 'string' ? text : undefined;\n}\n\n/**\n * Pone los valores en las {{variables}} del texto; una variable sin valor se queda como está.\n *\n * @param {string} text\n * @param {object|undefined} values\n * @returns {string}\n */\nfunction interpolate(text, values) {\n return text.replace(INTERPOLATION, (placeholder, name) => (values?.[name] === undefined ? placeholder : String(values[name])));\n}\n\n/**\n * El texto de una llave en los textos propios de los componentes (la prop `texts` de un componente y los de ComponentTexts\n * de afuera), si alguno la trae. Cada capa es {namespace, texts} con la misma forma que ese namespace en los textos del\n * paquete (es.js): plurales con _one/_other y {{variables}}. La primera capa que trae la llave gana.\n *\n * @param {Array<{namespace: string, texts: object|undefined}>} layers de la más cercana a la más lejana\n * @param {string} namespace el de la llave\n * @param {string} key la llave sin namespace\n * @param {object|undefined} values\n * @param {string} language para elegir el plural\n * @returns {string|undefined} el texto ya con sus variables, o undefined si ninguna capa lo trae\n */\nexport function componentTextOf(layers, namespace, key, values, language) {\n for (const layer of layers) {\n if (layer.namespace !== namespace || !layer.texts) {\n continue;\n }\n const text = textOf({[namespace]: layer.texts}, namespace, key, values, language);\n if (text !== undefined) {\n return interpolate(text, values);\n }\n }\n\n return undefined;\n}\n\n/**\n * El texto de una llave con una configuración dada (la del proveedor o la vigente).\n *\n * @param {{language: string, texts: object, translate: Function|null}} settings\n * @param {string} defaultNamespace el namespace cuando la llave no trae uno («table», «common», «problems»...)\n * @param {string} key «llave» o «namespace:llave»\n * @param {object} [values] las variables del texto y, para el plural, count\n * @returns {string} la llave misma si no hay texto, para que se note qué falta\n */\nexport function translateWith(settings, defaultNamespace, key, values) {\n const [namespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];\n const projectText = settings.translate?.(namespace, plainKey, values);\n if (typeof projectText === 'string') {\n return projectText;\n }\n\n const text = textOf(settings.texts?.[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[DEFAULT_LANGUAGE], namespace, plainKey, values, DEFAULT_LANGUAGE);\n\n if (text !== undefined) {\n return interpolate(text, values);\n }\n // como en i18next: sin la llave en ningún lado, el texto por omisión que pidió quien llama (un globo opcional pasa ''\n // y no se pinta); sin él, la llave tal cual, para que se note qué falta\n if (typeof values?.defaultValue === 'string') {\n return interpolate(values.defaultValue, values);\n }\n return `${namespace}${NAMESPACE_SEPARATOR}${plainKey}`;\n}\n\n/**\n * El texto de una llave con la configuración vigente, para lo que no es componente (avisos, errores del servidor).\n *\n * @param {string} defaultNamespace\n * @param {string} key\n * @param {object} [values]\n * @returns {string}\n */\nexport function translateToolkit(defaultNamespace, key, values) {\n return translateWith(currentSettings, defaultNamespace, key, values);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolkitSettings.js","sources":["../../src/toolkit/toolkitSettings.js"],"sourcesContent":["// La configuración del paquete: idioma, textos, zona horaria, moneda, nombre de la aplicación y navegación.\n//\n// La pone ToolkitProvider en cada render y la leen también las funciones que no son componentes (formatos de fecha y\n// número, avisos, errores del servidor). Sin proveedor valen los de omisión: español, la zona del navegador y la\n// navegación del navegador.\n//\n// Los textos se resuelven en este orden, para que cada proyecto cambie solo lo que necesite:\n// 1. translate del proyecto (por ejemplo el t de i18next), si regresa un texto;\n// 2. los textos que el proyecto pasó en `texts`, del idioma activo;\n// 3. los textos del paquete (locales/), del idioma activo y, si no está, en español.\n// Las llaves usan la forma de i18next: «namespace:llave.anidada», {{variable}} y plurales con _one / _other.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {createLogger} from '@/observability/logger.js';\nimport es from '@/locales/es.js';\nimport en from '@/locales/en.js';\n\nexport const DEFAULT_LANGUAGE = 'es';\n// la moneda de los montos (código ISO 4217) cuando el proyecto no dice otra\nexport const DEFAULT_CURRENCY = 'MXN';\n\n/**\n * Cómo se escribe la hora: de 24 horas («15:10», la de omisión) o de 12 con a.m. y p.m. («3:10 p.m.»). Son los valores de\n * `hourCycle` de Intl, por eso se ven así.\n */\nexport const HOUR_CYCLE = Object.freeze({\n twentyFourHours: 'h23',\n twelveHours: 'h12',\n});\nexport const DEFAULT_HOUR_CYCLE = HOUR_CYCLE.twentyFourHours;\n\nconst PACKAGE_TEXTS_BY_LANGUAGE = Object.freeze({es, en});\n\n/**\n * Los idiomas que ofrece la app cuando el proyecto no dice otros: su código, su nombre en su propio idioma (así lo busca quien\n * lo habla) y cómo se escriben sus números y fechas (Intl). El proyecto agrega los suyos en ToolkitProvider `languages` y pone\n * sus traducciones en `texts` (lo que no traduzca sale en español); los textos del paquete solo vienen en español e inglés.\n */\nexport const DEFAULT_LANGUAGES = Object.freeze([\n Object.freeze({code: 'es', label: 'Español', locale: 'es-MX'}),\n Object.freeze({code: 'en', label: 'English', locale: 'en-US'}),\n]);\n\nconst NAMESPACE_SEPARATOR = ':';\nconst KEY_SEPARATOR = '.';\nconst PLURAL_SEPARATOR = '_';\nconst PLURAL_OTHER = 'other';\nconst INTERPOLATION = /\\{\\{\\s*(\\w+)\\s*\\}\\}/g;\n\n/**\n * La zona horaria del navegador; si el navegador no la sabe, la de la Ciudad de México.\n *\n * @returns {string}\n */\nexport function browserTimeZone() {\n return Intl.DateTimeFormat().resolvedOptions().timeZone ?? 'America/Mexico_City';\n}\n\nlet currentSettings = Object.freeze({\n language: DEFAULT_LANGUAGE,\n texts: {},\n translate: null,\n timeZone: browserTimeZone(),\n currency: DEFAULT_CURRENCY,\n // la hora de 24 o de 12 horas (HOUR_CYCLE)\n hourCycle: DEFAULT_HOUR_CYCLE,\n appName: '',\n // la compilación del front que corre en esta pestaña ('' en desarrollo): con ella se sabe si hay una versión nueva\n buildId: '',\n // los idiomas que ofrece la app (DEFAULT_LANGUAGES)\n languages: DEFAULT_LANGUAGES,\n // a quién avisarle de un texto que no existe (reportMissingText); sin él, un aviso en la consola\n onMissingText: null,\n});\n\n/**\n * Cambia la configuración que leen las funciones del paquete. La llama ToolkitProvider; un proyecto sin React (o una\n * prueba) la puede llamar directo.\n *\n * @param {{language?: string, texts?: object, translate?: Function|null, timeZone?: string, currency?: string, hourCycle?: 'h23'|'h12', appName?: string, buildId?: string, languages?: Array<{code: string, label: string, locale?: string}>, onMissingText?: Function|null}} settings\n * @returns {void}\n */\nexport function configureToolkit(settings) {\n currentSettings = Object.freeze({...currentSettings, ...settings});\n}\n\n/**\n * La configuración vigente.\n *\n * @returns {{language: string, texts: object, translate: Function|null, timeZone: string, currency: string, hourCycle: 'h23'|'h12', appName: string, buildId: string, languages: Array<{code: string, label: string, locale?: string}>}}\n */\nexport function toolkitSettings() {\n return currentSettings;\n}\n\n/**\n * El locale de Intl del idioma: el que dice su lista de idiomas (es → es-MX, pt → pt-BR) o, si no dice, el código mismo\n * (Intl entiende «pt»). OJO: antes un idioma que no fuera es ni en salía con los números y las fechas de México.\n *\n * @param {string} language\n * @param {Array<{code: string, locale?: string}>} [languages] por omisión los de la configuración vigente\n * @returns {string}\n */\nexport function intlLocaleOf(language, languages = currentSettings.languages) {\n const known = languages?.find((entry) => entry.code === language) ?? DEFAULT_LANGUAGES.find((entry) => entry.code === language);\n return known?.locale ?? language ?? DEFAULT_LANGUAGES[0].locale;\n}\n\n/**\n * Lo que hay en una ruta de llaves («toast.error») dentro de un objeto de textos.\n *\n * @param {object|undefined} texts\n * @param {string} path\n * @returns {unknown}\n */\nfunction valueAtPath(texts, path) {\n let value = texts;\n for (const part of path.split(KEY_SEPARATOR)) {\n if (value === null || typeof value !== 'object') {\n return undefined;\n }\n value = value[part];\n }\n\n return value;\n}\n\n/**\n * El texto de una llave en un objeto de textos, con su plural si trae count (como i18next: llave_one, llave_other).\n *\n * @param {object|undefined} texts los textos de un idioma, por namespace\n * @param {string} namespace\n * @param {string} key\n * @param {object|undefined} values\n * @param {string} language\n * @returns {string|undefined}\n */\nfunction textOf(texts, namespace, key, values, language) {\n const namespaceTexts = texts?.[namespace];\n if (typeof values?.count === 'number') {\n const pluralCategory = new Intl.PluralRules(intlLocaleOf(language)).select(values.count);\n const pluralText = valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${pluralCategory}`)\n ?? valueAtPath(namespaceTexts, `${key}${PLURAL_SEPARATOR}${PLURAL_OTHER}`);\n if (typeof pluralText === 'string') {\n return pluralText;\n }\n }\n\n const text = valueAtPath(namespaceTexts, key);\n\n return typeof text === 'string' ? text : undefined;\n}\n\n/**\n * Pone los valores en las {{variables}} del texto; una variable sin valor se queda como está.\n *\n * @param {string} text\n * @param {object|undefined} values\n * @returns {string}\n */\nfunction interpolate(text, values) {\n return text.replace(INTERPOLATION, (placeholder, name) => (values?.[name] === undefined ? placeholder : String(values[name])));\n}\n\n/**\n * El texto de una llave en los textos propios de los componentes (la prop `texts` de un componente y los de ComponentTexts\n * de afuera), si alguno la trae. Cada capa es {namespace, texts} con la misma forma que ese namespace en los textos del\n * paquete (es.js): plurales con _one/_other y {{variables}}. La primera capa que trae la llave gana.\n *\n * @param {Array<{namespace: string, texts: object|undefined}>} layers de la más cercana a la más lejana\n * @param {string} namespace el de la llave\n * @param {string} key la llave sin namespace\n * @param {object|undefined} values\n * @param {string} language para elegir el plural\n * @returns {string|undefined} el texto ya con sus variables, o undefined si ninguna capa lo trae\n */\nexport function componentTextOf(layers, namespace, key, values, language) {\n for (const layer of layers) {\n if (layer.namespace !== namespace || !layer.texts) {\n continue;\n }\n const text = textOf({[namespace]: layer.texts}, namespace, key, values, language);\n if (text !== undefined) {\n return interpolate(text, values);\n }\n }\n\n return undefined;\n}\n\n/**\n * El texto de una llave con una configuración dada (la del proveedor o la vigente).\n *\n * @param {{language: string, texts: object, translate: Function|null, onMissingText?: Function|null}} settings\n * @param {string} defaultNamespace el namespace cuando la llave no trae uno («table», «common», «problems»...)\n * @param {string} key «llave» o «namespace:llave»\n * @param {object} [values] las variables del texto y, para el plural, count. Con `defaultValue` el texto es opcional: si no\n * existe se usa ese y no se avisa\n * @returns {string} la llave misma si no hay texto, para que se note qué falta (y se avisa: reportMissingText)\n */\nexport function translateWith(settings, defaultNamespace, key, values) {\n const [namespace, plainKey] = key.includes(NAMESPACE_SEPARATOR) ? key.split(NAMESPACE_SEPARATOR, 2) : [defaultNamespace, key];\n const projectText = settings.translate?.(namespace, plainKey, values);\n if (typeof projectText === 'string') {\n return projectText;\n }\n\n const text = textOf(settings.texts?.[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[settings.language], namespace, plainKey, values, settings.language)\n ?? textOf(PACKAGE_TEXTS_BY_LANGUAGE[DEFAULT_LANGUAGE], namespace, plainKey, values, DEFAULT_LANGUAGE);\n\n if (text !== undefined) {\n return interpolate(text, values);\n }\n // como en i18next: sin la llave en ningún lado, el texto por omisión que pidió quien llama (un globo opcional pasa ''\n // y no se pinta); sin él, la llave tal cual, para que se note qué falta\n if (typeof values?.defaultValue === 'string') {\n return interpolate(values.defaultValue, values);\n }\n reportMissingText(settings, namespace, plainKey);\n return `${namespace}${NAMESPACE_SEPARATOR}${plainKey}`;\n}\n\nconst log = createLogger('texts');\n// los textos que faltan de los que ya se avisó en la consola: uno por idioma y llave, no uno por cada pintada\nconst warnedMissingTexts = new Set();\n\n/**\n * Avisa que un texto no existe. Sin aviso, la pantalla enseñaba la llave («profile:tabs.documents») y nadie se enteraba\n * hasta verla. Con onMissingText del proyecto (ToolkitProvider) se le avisa a él cada vez y decide (mandarlo a Sentry,\n * tronar una prueba); sin él, un aviso en la consola, una sola vez por idioma y llave (el nivel lo pone setLogLevel).\n *\n * @param {{language: string, onMissingText?: Function|null}} settings\n * @param {string} namespace\n * @param {string} key\n * @returns {void}\n */\nfunction reportMissingText(settings, namespace, key) {\n if (settings.onMissingText) {\n settings.onMissingText({namespace, key, language: settings.language});\n return;\n }\n const missingId = `${settings.language}${NAMESPACE_SEPARATOR}${namespace}${NAMESPACE_SEPARATOR}${key}`;\n if (warnedMissingTexts.has(missingId)) {\n return;\n }\n warnedMissingTexts.add(missingId);\n log.warn(`No hay texto para «${namespace}${NAMESPACE_SEPARATOR}${key}» en «${settings.language}»: la pantalla enseña la llave`);\n}\n\n/**\n * El texto de una llave con la configuración vigente, para lo que no es componente (avisos, errores del servidor).\n *\n * @param {string} defaultNamespace\n * @param {string} key\n * @param {object} [values]\n * @returns {string}\n */\nexport function translateToolkit(defaultNamespace, key, values) {\n return translateWith(currentSettings, defaultNamespace, key, values);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} props
|
|
3
|
-
* @param {boolean} props.open
|
|
4
|
-
* @param {() => void} props.onClose
|
|
5
|
-
* @param {string} props.title ya traducido («Historial de Q3 · ago 2026»)
|
|
6
|
-
* @param {import('react').ReactNode} [props.subtitle]
|
|
7
|
-
* @param {string} props.subjectKey
|
|
8
|
-
* @param {(tableRequest: object, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object}>} props.fetchPage
|
|
9
|
-
* @param {Record<string, object>} props.eventDictionary
|
|
10
|
-
* @param {Record<string, object>} [props.resultDictionary]
|
|
11
|
-
* @param {Array<object>} [props.extraColumns]
|
|
12
|
-
* @param {import('react').ReactNode} [props.header] va entre el subtítulo y la tabla (p. ej. pestañas que cambian lo que se
|
|
13
|
-
* consulta)
|
|
14
|
-
* @param {(row: any) => string|null} [props.eventSuffixOf] complemento del evento de un renglón (AuditTrailTable)
|
|
15
|
-
*/
|
|
16
|
-
export default function AuditTrailDialog(props: {
|
|
1
|
+
declare const AuditTrailDialog: (props: {
|
|
17
2
|
open: boolean;
|
|
18
3
|
onClose: () => void;
|
|
19
4
|
title: string;
|
|
@@ -29,4 +14,8 @@ export default function AuditTrailDialog(props: {
|
|
|
29
14
|
extraColumns?: Array<object>;
|
|
30
15
|
header?: import('react').ReactNode;
|
|
31
16
|
eventSuffixOf?: (row: any) => string | null;
|
|
32
|
-
}
|
|
17
|
+
} & {
|
|
18
|
+
slots?: Record<string, import('react').ElementType>;
|
|
19
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
20
|
+
}) => import("react").JSX.Element;
|
|
21
|
+
export default AuditTrailDialog;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {{activeCount?: number, onClear: () => void, children: import('react').ReactNode}} props children = el filtro
|
|
3
|
-
*/
|
|
4
|
-
export default function HeaderFilterPopover(props: {
|
|
1
|
+
declare const HeaderFilterPopover: (props: {
|
|
5
2
|
activeCount?: number;
|
|
6
3
|
onClear: () => void;
|
|
7
4
|
children: import('react').ReactNode;
|
|
8
|
-
}
|
|
5
|
+
} & {
|
|
6
|
+
slots?: Record<string, import('react').ElementType>;
|
|
7
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
8
|
+
}) => import("react").JSX.Element;
|
|
9
|
+
export default HeaderFilterPopover;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} props
|
|
3
|
-
* @param {string[]} [props.value]
|
|
4
|
-
* @param {(value: string[]) => void} props.onChange
|
|
5
|
-
* @param {Array<{value: string, total: number}>} [props.options] faceta del servidor
|
|
6
|
-
* @param {(value: string) => import('react').ReactNode} [props.renderOption] cómo se lee el valor (diccionario)
|
|
7
|
-
*/
|
|
8
|
-
export default function MultiSelectColumnFilter(props: {
|
|
1
|
+
declare const MultiSelectColumnFilter: (props: {
|
|
9
2
|
value?: string[];
|
|
10
3
|
onChange: (value: string[]) => void;
|
|
11
4
|
options?: Array<{
|
|
@@ -13,4 +6,8 @@ export default function MultiSelectColumnFilter(props: {
|
|
|
13
6
|
total: number;
|
|
14
7
|
}>;
|
|
15
8
|
renderOption?: (value: string) => import('react').ReactNode;
|
|
16
|
-
}
|
|
9
|
+
} & {
|
|
10
|
+
slots?: Record<string, import('react').ElementType>;
|
|
11
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
12
|
+
}) => import("react").JSX.Element;
|
|
13
|
+
export default MultiSelectColumnFilter;
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} props
|
|
3
|
-
* @param {string} props.label
|
|
4
|
-
* @param {boolean} [props.sortable]
|
|
5
|
-
* @param {{column: string, direction: 'asc'|'desc'}} [props.sortEntry]
|
|
6
|
-
* @param {() => void} [props.onSort]
|
|
7
|
-
* @param {() => void} [props.onClearSort]
|
|
8
|
-
* @param {boolean} [props.filterable]
|
|
9
|
-
* @param {number} [props.activeCount]
|
|
10
|
-
* @param {() => void} [props.onClear]
|
|
11
|
-
* @param {import('react').ReactNode} [props.children] el filtro de la columna
|
|
12
|
-
*/
|
|
13
|
-
export default function SortableFilterHeader(props: {
|
|
1
|
+
declare const SortableFilterHeader: (props: {
|
|
14
2
|
label: string;
|
|
15
3
|
sortable?: boolean;
|
|
16
4
|
sortEntry?: {
|
|
@@ -23,4 +11,8 @@ export default function SortableFilterHeader(props: {
|
|
|
23
11
|
activeCount?: number;
|
|
24
12
|
onClear?: () => void;
|
|
25
13
|
children?: import('react').ReactNode;
|
|
26
|
-
}
|
|
14
|
+
} & {
|
|
15
|
+
slots?: Record<string, import('react').ElementType>;
|
|
16
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
17
|
+
}) => import("react").JSX.Element;
|
|
18
|
+
export default SortableFilterHeader;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} [props]
|
|
3
|
-
* @param {boolean} [props.filtered]
|
|
4
|
-
* @param {string} [props.label] ya traducido
|
|
5
|
-
* @param {() => void} [props.onClearFilters]
|
|
6
|
-
* @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
|
|
7
|
-
*/
|
|
8
|
-
export default function EmptyState(props?: {
|
|
1
|
+
declare const EmptyState: (props: {
|
|
9
2
|
filtered?: boolean;
|
|
10
3
|
label?: string;
|
|
11
4
|
onClearFilters?: () => void;
|
|
12
5
|
texts?: object;
|
|
13
|
-
}
|
|
6
|
+
} & {
|
|
7
|
+
slots?: Record<string, import('react').ElementType>;
|
|
8
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export default EmptyState;
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} props
|
|
3
|
-
* @param {Array<object>} props.chipConfig lo que arma buildChipConfig
|
|
4
|
-
* @param {object} props.filters
|
|
5
|
-
* @param {(field: string, value: unknown) => void} props.onSetFilter
|
|
6
|
-
* @param {() => void} props.onClearAll
|
|
7
|
-
* @param {number} [props.quickActiveCount] accesos rápidos puestos que no tienen chip aquí
|
|
8
|
-
* @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
|
|
9
|
-
*/
|
|
10
|
-
export default function FilterChips(props: {
|
|
1
|
+
declare const FilterChips: (props: {
|
|
11
2
|
chipConfig: Array<object>;
|
|
12
3
|
filters: object;
|
|
13
4
|
onSetFilter: (field: string, value: unknown) => void;
|
|
14
5
|
onClearAll: () => void;
|
|
15
6
|
quickActiveCount?: number;
|
|
16
7
|
texts?: object;
|
|
17
|
-
}
|
|
8
|
+
} & {
|
|
9
|
+
slots?: Record<string, import('react').ElementType>;
|
|
10
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
11
|
+
}) => import("react").JSX.Element | null;
|
|
12
|
+
export default FilterChips;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
* @param {object} props
|
|
3
|
-
* @param {number} props.page cuenta desde 0
|
|
4
|
-
* @param {number} props.pageCount
|
|
5
|
-
* @param {(page: number) => void} props.onChange
|
|
6
|
-
* @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete
|
|
7
|
-
*/
|
|
8
|
-
export default function GoToPage(props: {
|
|
1
|
+
declare const GoToPage: (props: {
|
|
9
2
|
page: number;
|
|
10
3
|
pageCount: number;
|
|
11
4
|
onChange: (page: number) => void;
|
|
12
5
|
texts?: object;
|
|
13
|
-
}
|
|
6
|
+
} & {
|
|
7
|
+
slots?: Record<string, import('react').ElementType>;
|
|
8
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
9
|
+
}) => import("react").JSX.Element | null;
|
|
10
|
+
export default GoToPage;
|
|
@@ -1,83 +1,7 @@
|
|
|
1
1
|
import { SELECTION_PHONE_LAYOUT } from '../ui/actions/SelectionActions.js';
|
|
2
2
|
export { SELECTION_PHONE_LAYOUT };
|
|
3
3
|
export type RowSelection = import('./rowSelection.js').RowSelection;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {object} props
|
|
7
|
-
* @param {(params: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}, signal: AbortSignal) => Promise<{rows: any[], total: number, facets?: Record<string, Array<{value: any, total: number}> | number>, capped?: boolean}>} props.fetchPage
|
|
8
|
-
* page cuenta desde 0; toServerTableParams lo convierte a la query del API
|
|
9
|
-
* @param {string} props.queryKey cambia cuando cambia el CONJUNTO (no los filtros): dispara recarga
|
|
10
|
-
* @param {boolean} [props.enabled] false mientras la sección está oculta: una tabla que nadie ve no consulta
|
|
11
|
-
* @param {Array<object>} props.columns textColumn / facetColumn / detailColumn o columnas del DataGrid
|
|
12
|
-
* @param {Record<string, string>} [props.filterKinds]
|
|
13
|
-
* @param {Record<string, unknown>} [props.filterDefaults]
|
|
14
|
-
* @param {Array<object>} [props.chipConfig] buildChipConfig
|
|
15
|
-
* @param {Array<object>} [props.quickFilters] {field, facetKey, caption, allLabel, renderLabel, order, clears,
|
|
16
|
-
* isOverridden, renderExtra, allCountKey, hideAllCount}
|
|
17
|
-
* @param {string|null} [props.searchField] filtro de texto que se saca a la barra; null quita la caja
|
|
18
|
-
* @param {string} [props.searchPlaceholder]
|
|
19
|
-
* @param {boolean} [props.searchInBar] la caja de búsqueda va arriba, en la barra de la app (BarActions): en escritorio,
|
|
20
|
-
* como el buscador de una ventana de macOS; en el teléfono con cápsulas flota arriba con las demás; sin cápsulas se
|
|
21
|
-
* queda aquí. Por omisión no
|
|
22
|
-
* @param {boolean} [props.collapseSearchInBar] en la barra, sin usar se encoge a la lupa y se estira al picarla; por
|
|
23
|
-
* omisión sí (false: siempre abierta)
|
|
24
|
-
* @param {string} [props.emptyLabel]
|
|
25
|
-
* @param {(total: number) => string} [props.countLabel] "12 pedidos"; por defecto "12 registros"
|
|
26
|
-
* @param {number[]} [props.pageSizeOptions]
|
|
27
|
-
* @param {number} [props.defaultPageSize]
|
|
28
|
-
* @param {(row: any) => string|number} [props.getRowId]
|
|
29
|
-
* @param {string} [props.prefix] estado en la URL con este prefijo (nuqs); sin él, en memoria
|
|
30
|
-
* @param {unknown} [props.refreshToken] cambia para volver a consultar la misma página (después de una acción)
|
|
31
|
-
* @param {(summary: {total: number, capped: boolean}) => import('react').ReactNode} [props.footer]
|
|
32
|
-
* @param {import('react').ReactNode} [props.toolbarExtra] a la derecha del conteo (p. ej. el selector de año)
|
|
33
|
-
* @param {(summary: {countText: string, total: number, capped: boolean}) => import('react').ReactNode} [props.header] reemplaza
|
|
34
|
-
* el renglón del conteo: la página pinta título, conteo y controles en uno solo. countText ya viene traducido y con
|
|
35
|
-
* el tope
|
|
36
|
-
* @param {import('react').ReactNode} [props.beforeQuickFilters] arriba de los accesos rápidos (p. ej. las pestañas de producto)
|
|
37
|
-
* @param {Array<object>} [props.columnGroupingModel] bandas que agrupan columnas bajo un nombre, arriba de sus
|
|
38
|
-
* encabezados (columnGroupingModel del DataGrid). Con ellas el encabezado mide un renglón más
|
|
39
|
-
* @param {(params: any) => string} [props.getRowClassName]
|
|
40
|
-
* @param {(row: any) => boolean} [props.isRowVisible] cuáles renglones de la página se pintan; los demás se esconden
|
|
41
|
-
* SIN volver a consultar (p. ej. plegar un grupo de renglones). Sin ella se pintan todos. OJO: va con useCallback;
|
|
42
|
-
* una función nueva en cada pintada haría filtrar la página cada vez
|
|
43
|
-
* @param {boolean} [props.striped] renglones alternos (cebra) con el color de hover del tema; al pasar el cursor se usa
|
|
44
|
-
* el de «seleccionado» para que el renglón bajo el cursor se siga distinguiendo
|
|
45
|
-
* @param {(params: any) => number|'auto'|null} [props.getRowHeight]
|
|
46
|
-
* @param {boolean} [props.hideFooterWhenAllRowsFit] esconde el pie (el paginador) mientras todo lo que hay cabe en la
|
|
47
|
-
* página; si un día no cabe, el pie vuelve solo. Para tablas que casi nunca pasan de una página
|
|
48
|
-
* @param {boolean} [props.showGoToPage] «Ir a página N» junto al paginador; por omisión escondido (con las flechas basta en
|
|
49
|
-
* casi todas las tablas). Para listas de muchas páginas que se recorren por número
|
|
50
|
-
* @param {object} [props.gridSx] estilos extra del DataGrid (clases de renglón)
|
|
51
|
-
* @param {number} [props.maxGridHeight] alto máximo del contenedor; sin él la tabla crece con sus renglones (default)
|
|
52
|
-
* @param {string} [props.ariaLabel] nombre de la tabla para lectores de pantalla
|
|
53
|
-
* @param {string} [props.fixedColumn] campo de la columna que se queda pegada a la izquierda al deslizar de lado (como
|
|
54
|
-
* fixedSelectColumn de mui-datatables)
|
|
55
|
-
* @param {Array<{key: string, label: string, icon?: import('react').ReactNode, color?: 'inherit'|'primary'|'secondary'|'error'|'info'|'success'|'warning', isDisabled?: (selection: RowSelection) => boolean, onClick: (selection: RowSelection, helpers: {clearSelection: () => void, refresh: () => void}) => unknown}>} [props.selectionActions]
|
|
56
|
-
* con ellas cada renglón lleva su casilla y, al elegir, sale la barra de los elegidos con estas acciones. label ya
|
|
57
|
-
* traducido; onClick recibe la selección (con isAllMatching mande `filters`, no `ids`) y cómo quitar la selección y volver
|
|
58
|
-
* a consultar después de actuar
|
|
59
|
-
* @param {(row: any) => boolean} [props.isRowSelectable] cuáles renglones se pueden elegir (un pedido entregado no se cancela)
|
|
60
|
-
* @param {boolean} [props.allowSelectAllMatching] la casilla de arriba elige todos los que coinciden (la acción recibe los
|
|
61
|
-
* filtros) y el aviso deja quedarse solo con la página; por omisión sí. false: la casilla elige la página y nunca se
|
|
62
|
-
* ofrece «todos»
|
|
63
|
-
* @param {(selection: RowSelection) => void} [props.onSelectionChange] cada que cambia la selección; también enciende las
|
|
64
|
-
* casillas sin barra de acciones (la pantalla pinta las suyas)
|
|
65
|
-
* @param {'top'|'split'} [props.selectionPhoneLayout] SELECTION_PHONE_LAYOUT: en el teléfono con vidrio o minimalista, todo
|
|
66
|
-
* arriba (por omisión) o el conteo arriba y las acciones abajo. Sin vidrio, en el renglón como en escritorio
|
|
67
|
-
* @param {(request: {filters: Record<string, any>, sortOrders: Array<{column: string, direction: 'asc'|'desc'}>, page: number, pageSize: number}) => void} [props.onQueryChange]
|
|
68
|
-
* cada que cambia lo que pide la tabla (un filtro, el orden, la página), antes de consultar: para la lógica de negocio que
|
|
69
|
-
* depende de lo filtrado («si eligió Cancelados, enseñe el motivo»)
|
|
70
|
-
* @param {(result: {rows: any[], total: number, facets: object, capped: boolean}) => void} [props.onLoaded] cada que llega una
|
|
71
|
-
* página del servidor
|
|
72
|
-
* @param {(error: unknown) => void} [props.onLoadError] cuando la consulta falla (la tabla ya enseña su aviso con «Reintentar»)
|
|
73
|
-
* @param {object} [props.gridProps] lo demás del DataGrid de MUI, sobre todo sus eventos (onRowClick, onRowDoubleClick,
|
|
74
|
-
* onCellKeyDown…). OJO: lo que la tabla controla (paginar, ordenar y filtrar en el servidor, el alto, la selección) no se
|
|
75
|
-
* reemplaza desde aquí: para eso están sus props
|
|
76
|
-
* @param {object} [props.texts] los textos de la tabla que cambian, con la forma de `table` en los textos del paquete
|
|
77
|
-
* (src/locales/es.js), ya en el idioma de la pantalla: {selection: {clear: 'Deseleccionar'}, empty: {filtered: '…'}}.
|
|
78
|
-
* También les llegan a sus filtros de columna, sus chips y su barra de elegidos
|
|
79
|
-
*/
|
|
80
|
-
export default function ServerTable(props: {
|
|
4
|
+
declare const ServerTable: (props: {
|
|
81
5
|
fetchPage: (params: {
|
|
82
6
|
filters: Record<string, any>;
|
|
83
7
|
sortOrders: Array<{
|
|
@@ -131,10 +55,10 @@ export default function ServerTable(props: {
|
|
|
131
55
|
getRowHeight?: (params: any) => number | 'auto' | null;
|
|
132
56
|
hideFooterWhenAllRowsFit?: boolean;
|
|
133
57
|
showGoToPage?: boolean;
|
|
134
|
-
gridSx?: object;
|
|
58
|
+
gridSx?: object | Array<object> | Function;
|
|
135
59
|
maxGridHeight?: number;
|
|
136
60
|
ariaLabel?: string;
|
|
137
|
-
fixedColumn?: string;
|
|
61
|
+
fixedColumn?: string | string[];
|
|
138
62
|
selectionActions?: Array<{
|
|
139
63
|
key: string;
|
|
140
64
|
label: string;
|
|
@@ -167,5 +91,17 @@ export default function ServerTable(props: {
|
|
|
167
91
|
}) => void;
|
|
168
92
|
onLoadError?: (error: unknown) => void;
|
|
169
93
|
gridProps?: object;
|
|
94
|
+
renderCard?: (row: any, helpers: {
|
|
95
|
+
index: number;
|
|
96
|
+
}) => import('react').ReactNode;
|
|
97
|
+
view?: 'table' | 'cards';
|
|
98
|
+
defaultView?: 'table' | 'cards';
|
|
99
|
+
onViewChange?: (view: 'table' | 'cards') => void;
|
|
100
|
+
showViewToggle?: boolean;
|
|
101
|
+
cardSkeleton?: import('react').ReactNode;
|
|
170
102
|
texts?: object;
|
|
171
|
-
}
|
|
103
|
+
} & {
|
|
104
|
+
slots?: Record<string, import('react').ElementType>;
|
|
105
|
+
slotProps?: Record<string, object | ((partProps: object) => object)>;
|
|
106
|
+
}) => import("react").JSX.Element;
|
|
107
|
+
export default ServerTable;
|