@portnet/ui 6.0.2 → 6.0.3
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/CHANGELOG.md +652 -0
- package/dist/esm/index.js +72 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v2/__tests__/AppMain.test.js +130 -0
- package/dist/esm/v2/__tests__/AppMain.test.js.map +1 -0
- package/dist/esm/v2/__tests__/ChartFigure.test.js +180 -0
- package/dist/esm/v2/__tests__/ChartFigure.test.js.map +1 -0
- package/dist/esm/v2/__tests__/DataGridRowActionsPropagation.test.js +150 -0
- package/dist/esm/v2/__tests__/DataGridRowActionsPropagation.test.js.map +1 -0
- package/dist/esm/v2/__tests__/DrawerTactileTargets.test.js +93 -0
- package/dist/esm/v2/__tests__/DrawerTactileTargets.test.js.map +1 -0
- package/dist/esm/v2/__tests__/FieldError.test.js +71 -38
- package/dist/esm/v2/__tests__/FieldError.test.js.map +1 -1
- package/dist/esm/v2/__tests__/FieldNaming.test.js +160 -0
- package/dist/esm/v2/__tests__/FieldNaming.test.js.map +1 -0
- package/dist/esm/v2/__tests__/FieldWidth.test.js +11 -11
- package/dist/esm/v2/__tests__/FieldWidth.test.js.map +1 -1
- package/dist/esm/v2/__tests__/FileCard.test.js +18 -17
- package/dist/esm/v2/__tests__/FileCard.test.js.map +1 -1
- package/dist/esm/v2/__tests__/FormikCheckbox.test.js +87 -179
- package/dist/esm/v2/__tests__/FormikCheckbox.test.js.map +1 -1
- package/dist/esm/v2/__tests__/FormikDateTimePicker.test.js +32 -44
- package/dist/esm/v2/__tests__/FormikDateTimePicker.test.js.map +1 -1
- package/dist/esm/v2/__tests__/FormikDisplayWidth.test.js +101 -0
- package/dist/esm/v2/__tests__/FormikDisplayWidth.test.js.map +1 -0
- package/dist/esm/v2/__tests__/FormikRadioGroup.test.js +118 -199
- package/dist/esm/v2/__tests__/FormikRadioGroup.test.js.map +1 -1
- package/dist/esm/v2/__tests__/MobileRowCard.test.js +44 -42
- package/dist/esm/v2/__tests__/MobileRowCard.test.js.map +1 -1
- package/dist/esm/v2/__tests__/PreviewDrawer.test.js +165 -0
- package/dist/esm/v2/__tests__/PreviewDrawer.test.js.map +1 -0
- package/dist/esm/v2/__tests__/ReferentielFieldContainer.test.js +156 -0
- package/dist/esm/v2/__tests__/ReferentielFieldContainer.test.js.map +1 -0
- package/dist/esm/v2/__tests__/SectionErrorBoundary.test.js +37 -52
- package/dist/esm/v2/__tests__/SectionErrorBoundary.test.js.map +1 -1
- package/dist/esm/v2/__tests__/apiError.test.js +50 -69
- package/dist/esm/v2/__tests__/apiError.test.js.map +1 -1
- package/dist/esm/v2/__tests__/banned-patterns.test.js +41 -122
- package/dist/esm/v2/__tests__/banned-patterns.test.js.map +1 -1
- package/dist/esm/v2/__tests__/chart-palette.test.js +204 -0
- package/dist/esm/v2/__tests__/chart-palette.test.js.map +1 -0
- package/dist/esm/v2/__tests__/contrast-palette.test.js +42 -74
- package/dist/esm/v2/__tests__/contrast-palette.test.js.map +1 -1
- package/dist/esm/v2/__tests__/cssVariables.test.js +44 -51
- package/dist/esm/v2/__tests__/cssVariables.test.js.map +1 -1
- package/dist/esm/v2/__tests__/fileValidation.test.js +134 -0
- package/dist/esm/v2/__tests__/fileValidation.test.js.map +1 -0
- package/dist/esm/v2/__tests__/filterCriteria.test.js +321 -0
- package/dist/esm/v2/__tests__/filterCriteria.test.js.map +1 -0
- package/dist/esm/v2/__tests__/fmtDate.test.js +68 -0
- package/dist/esm/v2/__tests__/fmtDate.test.js.map +1 -0
- package/dist/esm/v2/__tests__/gap-leakage-refonte.test.js +218 -0
- package/dist/esm/v2/__tests__/gap-leakage-refonte.test.js.map +1 -0
- package/dist/esm/v2/__tests__/labels-merge.test.js +17 -21
- package/dist/esm/v2/__tests__/labels-merge.test.js.map +1 -1
- package/dist/esm/v2/__tests__/locale-fallback.test.js +35 -40
- package/dist/esm/v2/__tests__/locale-fallback.test.js.map +1 -1
- package/dist/esm/v2/__tests__/reviveSavedCriteria.test.js +143 -0
- package/dist/esm/v2/__tests__/reviveSavedCriteria.test.js.map +1 -0
- package/dist/esm/v2/__tests__/rowActions.test.js +182 -0
- package/dist/esm/v2/__tests__/rowActions.test.js.map +1 -0
- package/dist/esm/v2/__tests__/useFocusOnRouteChange.test.js +155 -0
- package/dist/esm/v2/__tests__/useFocusOnRouteChange.test.js.map +1 -0
- package/dist/esm/v2/__tests__/useFocusTrap.test.js +266 -402
- package/dist/esm/v2/__tests__/useFocusTrap.test.js.map +1 -1
- package/dist/esm/v2/__tests__/usePrefersReducedMotion.test.js +120 -0
- package/dist/esm/v2/__tests__/usePrefersReducedMotion.test.js.map +1 -0
- package/dist/esm/v2/components/Accordion.js +48 -70
- package/dist/esm/v2/components/Accordion.js.map +1 -1
- package/dist/esm/v2/components/ActionStrip.js +31 -43
- package/dist/esm/v2/components/ActionStrip.js.map +1 -1
- package/dist/esm/v2/components/Banner.js +25 -22
- package/dist/esm/v2/components/Banner.js.map +1 -1
- package/dist/esm/v2/components/Busy.js +14 -19
- package/dist/esm/v2/components/Busy.js.map +1 -1
- package/dist/esm/v2/components/Button.js +34 -45
- package/dist/esm/v2/components/Button.js.map +1 -1
- package/dist/esm/v2/components/CategoryTag.js +44 -27
- package/dist/esm/v2/components/CategoryTag.js.map +1 -1
- package/dist/esm/v2/components/Checkbox.js +32 -38
- package/dist/esm/v2/components/Checkbox.js.map +1 -1
- package/dist/esm/v2/components/Chip.js +23 -36
- package/dist/esm/v2/components/Chip.js.map +1 -1
- package/dist/esm/v2/components/Combobox.js +112 -136
- package/dist/esm/v2/components/Combobox.js.map +1 -1
- package/dist/esm/v2/components/CommandPalette.js +113 -198
- package/dist/esm/v2/components/CommandPalette.js.map +1 -1
- package/dist/esm/v2/components/ConfirmDialog.js +36 -45
- package/dist/esm/v2/components/ConfirmDialog.js.map +1 -1
- package/dist/esm/v2/components/DatePicker.js +78 -81
- package/dist/esm/v2/components/DatePicker.js.map +1 -1
- package/dist/esm/v2/components/DateRangePicker.js +63 -74
- package/dist/esm/v2/components/DateRangePicker.js.map +1 -1
- package/dist/esm/v2/components/DateTimePicker.js +81 -86
- package/dist/esm/v2/components/DateTimePicker.js.map +1 -1
- package/dist/esm/v2/components/Drawer.js +71 -65
- package/dist/esm/v2/components/Drawer.js.map +1 -1
- package/dist/esm/v2/components/Dropzone.js +130 -177
- package/dist/esm/v2/components/Dropzone.js.map +1 -1
- package/dist/esm/v2/components/EmptyState.js +9 -9
- package/dist/esm/v2/components/EmptyState.js.map +1 -1
- package/dist/esm/v2/components/FavoriteToggle.js +24 -33
- package/dist/esm/v2/components/FavoriteToggle.js.map +1 -1
- package/dist/esm/v2/components/Field.js +155 -59
- package/dist/esm/v2/components/Field.js.map +1 -1
- package/dist/esm/v2/components/FieldError.js +9 -13
- package/dist/esm/v2/components/FieldError.js.map +1 -1
- package/dist/esm/v2/components/FieldHelp.js +28 -49
- package/dist/esm/v2/components/FieldHelp.js.map +1 -1
- package/dist/esm/v2/components/FileCard.js +14 -19
- package/dist/esm/v2/components/FileCard.js.map +1 -1
- package/dist/esm/v2/components/FilterTab.js +22 -31
- package/dist/esm/v2/components/FilterTab.js.map +1 -1
- package/dist/esm/v2/components/ForbiddenPage.js +28 -8
- package/dist/esm/v2/components/ForbiddenPage.js.map +1 -1
- package/dist/esm/v2/components/FormGrid.js +48 -54
- package/dist/esm/v2/components/FormGrid.js.map +1 -1
- package/dist/esm/v2/components/FormikDisplay.js +98 -24
- package/dist/esm/v2/components/FormikDisplay.js.map +1 -1
- package/dist/esm/v2/components/Input.js +75 -34
- package/dist/esm/v2/components/Input.js.map +1 -1
- package/dist/esm/v2/components/KPICard.js +42 -51
- package/dist/esm/v2/components/KPICard.js.map +1 -1
- package/dist/esm/v2/components/KPIStrip.js +9 -15
- package/dist/esm/v2/components/KPIStrip.js.map +1 -1
- package/dist/esm/v2/components/KV.js +16 -23
- package/dist/esm/v2/components/KV.js.map +1 -1
- package/dist/esm/v2/components/KVGrid.js +15 -23
- package/dist/esm/v2/components/KVGrid.js.map +1 -1
- package/dist/esm/v2/components/Layout.js +81 -117
- package/dist/esm/v2/components/Layout.js.map +1 -1
- package/dist/esm/v2/components/MobileRowCard.js +64 -75
- package/dist/esm/v2/components/MobileRowCard.js.map +1 -1
- package/dist/esm/v2/components/Modal.js +44 -53
- package/dist/esm/v2/components/Modal.js.map +1 -1
- package/dist/esm/v2/components/NetworkErrorPage.js +28 -11
- package/dist/esm/v2/components/NetworkErrorPage.js.map +1 -1
- package/dist/esm/v2/components/NotFoundPage.js +28 -9
- package/dist/esm/v2/components/NotFoundPage.js.map +1 -1
- package/dist/esm/v2/components/NumberInput.js +77 -107
- package/dist/esm/v2/components/NumberInput.js.map +1 -1
- package/dist/esm/v2/components/OverflowMenu.js +24 -42
- package/dist/esm/v2/components/OverflowMenu.js.map +1 -1
- package/dist/esm/v2/components/PdfViewer.js +24 -33
- package/dist/esm/v2/components/PdfViewer.js.map +1 -1
- package/dist/esm/v2/components/ProgressBar.js +28 -36
- package/dist/esm/v2/components/ProgressBar.js.map +1 -1
- package/dist/esm/v2/components/Radio.js +49 -57
- package/dist/esm/v2/components/Radio.js.map +1 -1
- package/dist/esm/v2/components/SectionErrorBoundary.js +84 -130
- package/dist/esm/v2/components/SectionErrorBoundary.js.map +1 -1
- package/dist/esm/v2/components/SectionHeader.js +24 -31
- package/dist/esm/v2/components/SectionHeader.js.map +1 -1
- package/dist/esm/v2/components/Segmented.js +59 -84
- package/dist/esm/v2/components/Segmented.js.map +1 -1
- package/dist/esm/v2/components/Select.js +100 -138
- package/dist/esm/v2/components/Select.js.map +1 -1
- package/dist/esm/v2/components/ServerErrorPage.js +27 -10
- package/dist/esm/v2/components/ServerErrorPage.js.map +1 -1
- package/dist/esm/v2/components/Skeleton.js +81 -96
- package/dist/esm/v2/components/Skeleton.js.map +1 -1
- package/dist/esm/v2/components/SkipLink.js +6 -7
- package/dist/esm/v2/components/SkipLink.js.map +1 -1
- package/dist/esm/v2/components/Spinner.js +13 -22
- package/dist/esm/v2/components/Spinner.js.map +1 -1
- package/dist/esm/v2/components/Status.js +14 -25
- package/dist/esm/v2/components/Status.js.map +1 -1
- package/dist/esm/v2/components/Stepper.js +68 -71
- package/dist/esm/v2/components/Stepper.js.map +1 -1
- package/dist/esm/v2/components/Surface.js +25 -44
- package/dist/esm/v2/components/Surface.js.map +1 -1
- package/dist/esm/v2/components/Switch.js +21 -29
- package/dist/esm/v2/components/Switch.js.map +1 -1
- package/dist/esm/v2/components/TabPanel.js +84 -0
- package/dist/esm/v2/components/TabPanel.js.map +1 -0
- package/dist/esm/v2/components/Tabs.js +43 -19
- package/dist/esm/v2/components/Tabs.js.map +1 -1
- package/dist/esm/v2/components/TelInput.js +75 -108
- package/dist/esm/v2/components/TelInput.js.map +1 -1
- package/dist/esm/v2/components/Textarea.js +21 -30
- package/dist/esm/v2/components/Textarea.js.map +1 -1
- package/dist/esm/v2/components/TimePicker.js +59 -69
- package/dist/esm/v2/components/TimePicker.js.map +1 -1
- package/dist/esm/v2/components/Toast.js +109 -163
- package/dist/esm/v2/components/Toast.js.map +1 -1
- package/dist/esm/v2/components/Tooltip.js +18 -31
- package/dist/esm/v2/components/Tooltip.js.map +1 -1
- package/dist/esm/v2/components/_ErrorPageBody.js +6 -5
- package/dist/esm/v2/components/_ErrorPageBody.js.map +1 -1
- package/dist/esm/v2/components/_pickerShared.js +2 -2
- package/dist/esm/v2/components/_pickerShared.js.map +1 -1
- package/dist/esm/v2/components/index.js +37 -0
- package/dist/esm/v2/components/index.js.map +1 -1
- package/dist/esm/v2/hooks/index.js +62 -0
- package/dist/esm/v2/hooks/index.js.map +1 -1
- package/dist/esm/v2/hooks/useAppliedFilters.js +112 -0
- package/dist/esm/v2/hooks/useAppliedFilters.js.map +1 -0
- package/dist/esm/v2/hooks/useDebouncedCallback.js +82 -0
- package/dist/esm/v2/hooks/useDebouncedCallback.js.map +1 -0
- package/dist/esm/v2/hooks/useDelayedFlag.js +5 -19
- package/dist/esm/v2/hooks/useDelayedFlag.js.map +1 -1
- package/dist/esm/v2/hooks/useDensity.js +13 -17
- package/dist/esm/v2/hooks/useDensity.js.map +1 -1
- package/dist/esm/v2/hooks/useFocusFirstError.js +25 -33
- package/dist/esm/v2/hooks/useFocusFirstError.js.map +1 -1
- package/dist/esm/v2/hooks/useFocusOnRouteChange.js +81 -0
- package/dist/esm/v2/hooks/useFocusOnRouteChange.js.map +1 -0
- package/dist/esm/v2/hooks/useFocusTrap.js +19 -23
- package/dist/esm/v2/hooks/useFocusTrap.js.map +1 -1
- package/dist/esm/v2/hooks/useFormAutoSave.js +38 -53
- package/dist/esm/v2/hooks/useFormAutoSave.js.map +1 -1
- package/dist/esm/v2/hooks/useFormCompletionProgress.js +32 -51
- package/dist/esm/v2/hooks/useFormCompletionProgress.js.map +1 -1
- package/dist/esm/v2/hooks/useKeyboardShortcuts.js +125 -0
- package/dist/esm/v2/hooks/useKeyboardShortcuts.js.map +1 -0
- package/dist/esm/v2/hooks/usePrefersReducedMotion.js +99 -0
- package/dist/esm/v2/hooks/usePrefersReducedMotion.js.map +1 -0
- package/dist/esm/v2/hooks/useResolvedDensity.js +2 -10
- package/dist/esm/v2/hooks/useResolvedDensity.js.map +1 -1
- package/dist/esm/v2/hooks/useSortedRows.js +3 -5
- package/dist/esm/v2/hooks/useSortedRows.js.map +1 -1
- package/dist/esm/v2/hooks/useTabLoading.js +6 -21
- package/dist/esm/v2/hooks/useTabLoading.js.map +1 -1
- package/dist/esm/v2/index.js +2 -3
- package/dist/esm/v2/index.js.map +1 -1
- package/dist/esm/v2/modalContext.js +2 -2
- package/dist/esm/v2/modalContext.js.map +1 -1
- package/dist/esm/v2/models/favorite.js.map +1 -1
- package/dist/esm/v2/models/personalization.js.map +1 -1
- package/dist/esm/v2/models/referentiel.js.map +1 -1
- package/dist/esm/v2/models/savedFilter.js.map +1 -1
- package/dist/esm/v2/patterns/ActionBar.js +115 -159
- package/dist/esm/v2/patterns/ActionBar.js.map +1 -1
- package/dist/esm/v2/patterns/AppMain.js +108 -0
- package/dist/esm/v2/patterns/AppMain.js.map +1 -0
- package/dist/esm/v2/patterns/BulkActionBar.js +31 -34
- package/dist/esm/v2/patterns/BulkActionBar.js.map +1 -1
- package/dist/esm/v2/patterns/ChartFigure.js +151 -0
- package/dist/esm/v2/patterns/ChartFigure.js.map +1 -0
- package/dist/esm/v2/patterns/CollapsibleDataGrid.js +111 -152
- package/dist/esm/v2/patterns/CollapsibleDataGrid.js.map +1 -1
- package/dist/esm/v2/patterns/ColumnsToggle.js +43 -77
- package/dist/esm/v2/patterns/ColumnsToggle.js.map +1 -1
- package/dist/esm/v2/patterns/DataGrid.js +221 -255
- package/dist/esm/v2/patterns/DataGrid.js.map +1 -1
- package/dist/esm/v2/patterns/DataGridSettingsMenu.js +76 -94
- package/dist/esm/v2/patterns/DataGridSettingsMenu.js.map +1 -1
- package/dist/esm/v2/patterns/DataGridToolbar.js +85 -89
- package/dist/esm/v2/patterns/DataGridToolbar.js.map +1 -1
- package/dist/esm/v2/patterns/DataGridVirtualized.js +141 -182
- package/dist/esm/v2/patterns/DataGridVirtualized.js.map +1 -1
- package/dist/esm/v2/patterns/DeleteResourceConfirmDialog.js +26 -30
- package/dist/esm/v2/patterns/DeleteResourceConfirmDialog.js.map +1 -1
- package/dist/esm/v2/patterns/DetailSplit.js +108 -0
- package/dist/esm/v2/patterns/DetailSplit.js.map +1 -0
- package/dist/esm/v2/patterns/FavoriteColumn.js +15 -17
- package/dist/esm/v2/patterns/FavoriteColumn.js.map +1 -1
- package/dist/esm/v2/patterns/FavoritesFilter.js +30 -39
- package/dist/esm/v2/patterns/FavoritesFilter.js.map +1 -1
- package/dist/esm/v2/patterns/FilterTabBar.js +112 -0
- package/dist/esm/v2/patterns/FilterTabBar.js.map +1 -0
- package/dist/esm/v2/patterns/FormErrorSummary.js +12 -13
- package/dist/esm/v2/patterns/FormErrorSummary.js.map +1 -1
- package/dist/esm/v2/patterns/FormPageShell.js +43 -41
- package/dist/esm/v2/patterns/FormPageShell.js.map +1 -1
- package/dist/esm/v2/patterns/FormSection.js +30 -38
- package/dist/esm/v2/patterns/FormSection.js.map +1 -1
- package/dist/esm/v2/patterns/FormikCheckbox.js +29 -39
- package/dist/esm/v2/patterns/FormikCheckbox.js.map +1 -1
- package/dist/esm/v2/patterns/FormikCheckboxGroup.js +56 -60
- package/dist/esm/v2/patterns/FormikCheckboxGroup.js.map +1 -1
- package/dist/esm/v2/patterns/FormikCombobox.js +51 -69
- package/dist/esm/v2/patterns/FormikCombobox.js.map +1 -1
- package/dist/esm/v2/patterns/FormikDatePicker.js +44 -58
- package/dist/esm/v2/patterns/FormikDatePicker.js.map +1 -1
- package/dist/esm/v2/patterns/FormikDateTimePicker.js +44 -58
- package/dist/esm/v2/patterns/FormikDateTimePicker.js.map +1 -1
- package/dist/esm/v2/patterns/FormikErrorFocus.js +22 -23
- package/dist/esm/v2/patterns/FormikErrorFocus.js.map +1 -1
- package/dist/esm/v2/patterns/FormikErrorSummary.js +89 -0
- package/dist/esm/v2/patterns/FormikErrorSummary.js.map +1 -0
- package/dist/esm/v2/patterns/FormikFile.js +94 -78
- package/dist/esm/v2/patterns/FormikFile.js.map +1 -1
- package/dist/esm/v2/patterns/FormikInput.js +40 -53
- package/dist/esm/v2/patterns/FormikInput.js.map +1 -1
- package/dist/esm/v2/patterns/FormikRadioGroup.js +39 -51
- package/dist/esm/v2/patterns/FormikRadioGroup.js.map +1 -1
- package/dist/esm/v2/patterns/FormikReferentielField.js +49 -59
- package/dist/esm/v2/patterns/FormikReferentielField.js.map +1 -1
- package/dist/esm/v2/patterns/FormikSelect.js +64 -87
- package/dist/esm/v2/patterns/FormikSelect.js.map +1 -1
- package/dist/esm/v2/patterns/FormikTextarea.js +30 -46
- package/dist/esm/v2/patterns/FormikTextarea.js.map +1 -1
- package/dist/esm/v2/patterns/KeyboardShortcutsHelp.js +53 -71
- package/dist/esm/v2/patterns/KeyboardShortcutsHelp.js.map +1 -1
- package/dist/esm/v2/patterns/NetworkErrorBanner.js +6 -7
- package/dist/esm/v2/patterns/NetworkErrorBanner.js.map +1 -1
- package/dist/esm/v2/patterns/PageContent.js +10 -14
- package/dist/esm/v2/patterns/PageContent.js.map +1 -1
- package/dist/esm/v2/patterns/PreviewDrawer.js +153 -0
- package/dist/esm/v2/patterns/PreviewDrawer.js.map +1 -0
- package/dist/esm/v2/patterns/ReferentielField.js +327 -312
- package/dist/esm/v2/patterns/ReferentielField.js.map +1 -1
- package/dist/esm/v2/patterns/RowFavoriteToggle.js +27 -22
- package/dist/esm/v2/patterns/RowFavoriteToggle.js.map +1 -1
- package/dist/esm/v2/patterns/SaveFilterDialog.js +38 -66
- package/dist/esm/v2/patterns/SaveFilterDialog.js.map +1 -1
- package/dist/esm/v2/patterns/SavedFiltersMenu.js +62 -81
- package/dist/esm/v2/patterns/SavedFiltersMenu.js.map +1 -1
- package/dist/esm/v2/patterns/SkeletonPageShell.js +106 -129
- package/dist/esm/v2/patterns/SkeletonPageShell.js.map +1 -1
- package/dist/esm/v2/patterns/SortableHeader.js +22 -45
- package/dist/esm/v2/patterns/SortableHeader.js.map +1 -1
- package/dist/esm/v2/patterns/Tour.js +94 -120
- package/dist/esm/v2/patterns/Tour.js.map +1 -1
- package/dist/esm/v2/patterns/_dataGridShared.js +107 -128
- package/dist/esm/v2/patterns/_dataGridShared.js.map +1 -1
- package/dist/esm/v2/patterns/_pickerSerialisation.js +6 -8
- package/dist/esm/v2/patterns/_pickerSerialisation.js.map +1 -1
- package/dist/esm/v2/patterns/_sort.js +17 -33
- package/dist/esm/v2/patterns/_sort.js.map +1 -1
- package/dist/esm/v2/patterns/_useColumnReorder.js +122 -160
- package/dist/esm/v2/patterns/_useColumnReorder.js.map +1 -1
- package/dist/esm/v2/patterns/_useColumnResize.js +78 -96
- package/dist/esm/v2/patterns/_useColumnResize.js.map +1 -1
- package/dist/esm/v2/patterns/filterCriteria.js +102 -0
- package/dist/esm/v2/patterns/filterCriteria.js.map +1 -0
- package/dist/esm/v2/patterns/index.js +152 -0
- package/dist/esm/v2/patterns/index.js.map +1 -1
- package/dist/esm/v2/patterns/rowActions.js +223 -0
- package/dist/esm/v2/patterns/rowActions.js.map +1 -0
- package/dist/esm/v2/personalization/PersonalizationProvider.js +50 -47
- package/dist/esm/v2/personalization/PersonalizationProvider.js.map +1 -1
- package/dist/esm/v2/personalization/adapters/_storageKey.js +5 -5
- package/dist/esm/v2/personalization/adapters/_storageKey.js.map +1 -1
- package/dist/esm/v2/personalization/adapters/createLocalStorageAdapter.js +22 -23
- package/dist/esm/v2/personalization/adapters/createLocalStorageAdapter.js.map +1 -1
- package/dist/esm/v2/personalization/adapters/createMemoryAdapter.js +13 -13
- package/dist/esm/v2/personalization/adapters/createMemoryAdapter.js.map +1 -1
- package/dist/esm/v2/personalization/capabilities/favorites.js +36 -60
- package/dist/esm/v2/personalization/capabilities/favorites.js.map +1 -1
- package/dist/esm/v2/personalization/capabilities/favoritesView.js +22 -34
- package/dist/esm/v2/personalization/capabilities/favoritesView.js.map +1 -1
- package/dist/esm/v2/personalization/capabilities/gridPreferences.js +28 -34
- package/dist/esm/v2/personalization/capabilities/gridPreferences.js.map +1 -1
- package/dist/esm/v2/personalization/capabilities/reviveSavedCriteria.js +119 -0
- package/dist/esm/v2/personalization/capabilities/reviveSavedCriteria.js.map +1 -0
- package/dist/esm/v2/personalization/capabilities/savedFilters.js +90 -98
- package/dist/esm/v2/personalization/capabilities/savedFilters.js.map +1 -1
- package/dist/esm/v2/personalization/createPersonalizationStore.js +78 -181
- package/dist/esm/v2/personalization/createPersonalizationStore.js.map +1 -1
- package/dist/esm/v2/personalization/index.js +17 -0
- package/dist/esm/v2/personalization/index.js.map +1 -1
- package/dist/esm/v2/personalization/personalizationContext.js +9 -9
- package/dist/esm/v2/personalization/personalizationContext.js.map +1 -1
- package/dist/esm/v2/personalization/schema.js +8 -9
- package/dist/esm/v2/personalization/schema.js.map +1 -1
- package/dist/esm/v2/referentiel/ReferentielProvider.js +27 -42
- package/dist/esm/v2/referentiel/ReferentielProvider.js.map +1 -1
- package/dist/esm/v2/referentiel/types.js +2 -0
- package/dist/esm/v2/referentiel/types.js.map +1 -0
- package/dist/esm/v2/referentiel/useReferentielClient.js +10 -11
- package/dist/esm/v2/referentiel/useReferentielClient.js.map +1 -1
- package/dist/esm/v2/referentiel/useReferentielOptions.js +60 -117
- package/dist/esm/v2/referentiel/useReferentielOptions.js.map +1 -1
- package/dist/esm/v2/referentiel/useReferentielSearch.js +37 -91
- package/dist/esm/v2/referentiel/useReferentielSearch.js.map +1 -1
- package/dist/esm/v2/theme/_brand.js +8 -24
- package/dist/esm/v2/theme/_brand.js.map +1 -1
- package/dist/esm/v2/theme/_brandSecondary.js +8 -24
- package/dist/esm/v2/theme/_brandSecondary.js.map +1 -1
- package/dist/esm/v2/theme/createPortnetTheme.js +51 -61
- package/dist/esm/v2/theme/createPortnetTheme.js.map +1 -1
- package/dist/esm/v2/theme/cssVariables.js +62 -69
- package/dist/esm/v2/theme/cssVariables.js.map +1 -1
- package/dist/esm/v2/theme/index.js +5 -5
- package/dist/esm/v2/theme/index.js.map +1 -1
- package/dist/esm/v2/tokens/breakpoints.js +14 -14
- package/dist/esm/v2/tokens/breakpoints.js.map +1 -1
- package/dist/esm/v2/tokens/chart.js +261 -0
- package/dist/esm/v2/tokens/chart.js.map +1 -0
- package/dist/esm/v2/tokens/colors.js +22 -22
- package/dist/esm/v2/tokens/colors.js.map +1 -1
- package/dist/esm/v2/tokens/density.js +62 -7
- package/dist/esm/v2/tokens/density.js.map +1 -1
- package/dist/esm/v2/tokens/index.js +49 -34
- package/dist/esm/v2/tokens/index.js.map +1 -1
- package/dist/esm/v2/tokens/motion.js +12 -20
- package/dist/esm/v2/tokens/motion.js.map +1 -1
- package/dist/esm/v2/tokens/radius.js +1 -1
- package/dist/esm/v2/tokens/radius.js.map +1 -1
- package/dist/esm/v2/tokens/shadows.js +6 -6
- package/dist/esm/v2/tokens/shadows.js.map +1 -1
- package/dist/esm/v2/tokens/spacing.js +2 -2
- package/dist/esm/v2/tokens/spacing.js.map +1 -1
- package/dist/esm/v2/tokens/state.js +1 -1
- package/dist/esm/v2/tokens/state.js.map +1 -1
- package/dist/esm/v2/tokens/statusPalette.js +17 -21
- package/dist/esm/v2/tokens/statusPalette.js.map +1 -1
- package/dist/esm/v2/tokens/tokens.json +6 -1
- package/dist/esm/v2/tokens/typography.js +13 -13
- package/dist/esm/v2/tokens/typography.js.map +1 -1
- package/dist/esm/v2/tokens/zIndex.js +1 -1
- package/dist/esm/v2/tokens/zIndex.js.map +1 -1
- package/dist/esm/v2/types/datagrid.js.map +1 -1
- package/dist/esm/v2/utils/apiError.js +16 -37
- package/dist/esm/v2/utils/apiError.js.map +1 -1
- package/dist/esm/v2/utils/contrast.js +31 -32
- package/dist/esm/v2/utils/contrast.js.map +1 -1
- package/dist/esm/v2/utils/cx.js +5 -25
- package/dist/esm/v2/utils/cx.js.map +1 -1
- package/dist/esm/v2/utils/fileDownload.js +23 -26
- package/dist/esm/v2/utils/fileDownload.js.map +1 -1
- package/dist/esm/v2/utils/fileValidation.js +209 -0
- package/dist/esm/v2/utils/fileValidation.js.map +1 -0
- package/dist/esm/v2/utils/fmtDate.js +111 -0
- package/dist/esm/v2/utils/fmtDate.js.map +1 -0
- package/dist/esm/v2/utils/fmtMoney.js +8 -10
- package/dist/esm/v2/utils/fmtMoney.js.map +1 -1
- package/dist/esm/v2/utils/formikErrors.js +78 -0
- package/dist/esm/v2/utils/formikErrors.js.map +1 -0
- package/dist/esm/v2/utils/index.js +35 -2
- package/dist/esm/v2/utils/index.js.map +1 -1
- package/dist/esm/v2/utils/mergeLabels.js +7 -12
- package/dist/esm/v2/utils/mergeLabels.js.map +1 -1
- package/dist/esm/v2/utils/networkStatus.js +12 -12
- package/dist/esm/v2/utils/networkStatus.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -49
- package/dist/index.js.map +1 -1
- package/dist/v2/__tests__/AppMain.test.js +133 -0
- package/dist/v2/__tests__/AppMain.test.js.map +1 -0
- package/dist/v2/__tests__/ChartFigure.test.js +183 -0
- package/dist/v2/__tests__/ChartFigure.test.js.map +1 -0
- package/dist/v2/__tests__/DataGridRowActionsPropagation.test.js +153 -0
- package/dist/v2/__tests__/DataGridRowActionsPropagation.test.js.map +1 -0
- package/dist/v2/__tests__/DrawerTactileTargets.test.js +94 -0
- package/dist/v2/__tests__/DrawerTactileTargets.test.js.map +1 -0
- package/dist/v2/__tests__/FieldError.test.js +82 -49
- package/dist/v2/__tests__/FieldError.test.js.map +1 -1
- package/dist/v2/__tests__/FieldNaming.test.js +161 -0
- package/dist/v2/__tests__/FieldNaming.test.js.map +1 -0
- package/dist/v2/__tests__/FieldWidth.test.js +23 -25
- package/dist/v2/__tests__/FieldWidth.test.js.map +1 -1
- package/dist/v2/__tests__/FileCard.test.js +29 -28
- package/dist/v2/__tests__/FileCard.test.js.map +1 -1
- package/dist/v2/__tests__/FormikCheckbox.test.js +90 -183
- package/dist/v2/__tests__/FormikCheckbox.test.js.map +1 -1
- package/dist/v2/__tests__/FormikDateTimePicker.test.js +38 -48
- package/dist/v2/__tests__/FormikDateTimePicker.test.js.map +1 -1
- package/dist/v2/__tests__/FormikDisplayWidth.test.js +102 -0
- package/dist/v2/__tests__/FormikDisplayWidth.test.js.map +1 -0
- package/dist/v2/__tests__/FormikRadioGroup.test.js +123 -204
- package/dist/v2/__tests__/FormikRadioGroup.test.js.map +1 -1
- package/dist/v2/__tests__/MobileRowCard.test.js +63 -61
- package/dist/v2/__tests__/MobileRowCard.test.js.map +1 -1
- package/dist/v2/__tests__/PreviewDrawer.test.js +169 -0
- package/dist/v2/__tests__/PreviewDrawer.test.js.map +1 -0
- package/dist/v2/__tests__/ReferentielFieldContainer.test.js +159 -0
- package/dist/v2/__tests__/ReferentielFieldContainer.test.js.map +1 -0
- package/dist/v2/__tests__/SectionErrorBoundary.test.js +53 -68
- package/dist/v2/__tests__/SectionErrorBoundary.test.js.map +1 -1
- package/dist/v2/__tests__/apiError.test.js +50 -69
- package/dist/v2/__tests__/apiError.test.js.map +1 -1
- package/dist/v2/__tests__/banned-patterns.test.js +42 -123
- package/dist/v2/__tests__/banned-patterns.test.js.map +1 -1
- package/dist/v2/__tests__/chart-palette.test.js +205 -0
- package/dist/v2/__tests__/chart-palette.test.js.map +1 -0
- package/dist/v2/__tests__/contrast-palette.test.js +42 -74
- package/dist/v2/__tests__/contrast-palette.test.js.map +1 -1
- package/dist/v2/__tests__/cssVariables.test.js +44 -51
- package/dist/v2/__tests__/cssVariables.test.js.map +1 -1
- package/dist/v2/__tests__/fileValidation.test.js +136 -0
- package/dist/v2/__tests__/fileValidation.test.js.map +1 -0
- package/dist/v2/__tests__/filterCriteria.test.js +324 -0
- package/dist/v2/__tests__/filterCriteria.test.js.map +1 -0
- package/dist/v2/__tests__/fmtDate.test.js +69 -0
- package/dist/v2/__tests__/fmtDate.test.js.map +1 -0
- package/dist/v2/__tests__/gap-leakage-refonte.test.js +221 -0
- package/dist/v2/__tests__/gap-leakage-refonte.test.js.map +1 -0
- package/dist/v2/__tests__/labels-merge.test.js +23 -27
- package/dist/v2/__tests__/labels-merge.test.js.map +1 -1
- package/dist/v2/__tests__/locale-fallback.test.js +47 -52
- package/dist/v2/__tests__/locale-fallback.test.js.map +1 -1
- package/dist/v2/__tests__/reviveSavedCriteria.test.js +144 -0
- package/dist/v2/__tests__/reviveSavedCriteria.test.js.map +1 -0
- package/dist/v2/__tests__/rowActions.test.js +186 -0
- package/dist/v2/__tests__/rowActions.test.js.map +1 -0
- package/dist/v2/__tests__/useFocusOnRouteChange.test.js +156 -0
- package/dist/v2/__tests__/useFocusOnRouteChange.test.js.map +1 -0
- package/dist/v2/__tests__/useFocusTrap.test.js +270 -407
- package/dist/v2/__tests__/useFocusTrap.test.js.map +1 -1
- package/dist/v2/__tests__/usePrefersReducedMotion.test.js +123 -0
- package/dist/v2/__tests__/usePrefersReducedMotion.test.js.map +1 -0
- package/dist/v2/components/Accordion.js +60 -82
- package/dist/v2/components/Accordion.js.map +1 -1
- package/dist/v2/components/ActionStrip.js +40 -52
- package/dist/v2/components/ActionStrip.js.map +1 -1
- package/dist/v2/components/Banner.js +42 -41
- package/dist/v2/components/Banner.js.map +1 -1
- package/dist/v2/components/Busy.js +22 -27
- package/dist/v2/components/Busy.js.map +1 -1
- package/dist/v2/components/Button.js +39 -50
- package/dist/v2/components/Button.js.map +1 -1
- package/dist/v2/components/CategoryTag.d.ts.map +1 -1
- package/dist/v2/components/CategoryTag.js +49 -32
- package/dist/v2/components/CategoryTag.js.map +1 -1
- package/dist/v2/components/Checkbox.js +39 -45
- package/dist/v2/components/Checkbox.js.map +1 -1
- package/dist/v2/components/Chip.js +29 -42
- package/dist/v2/components/Chip.js.map +1 -1
- package/dist/v2/components/Combobox.js +122 -144
- package/dist/v2/components/Combobox.js.map +1 -1
- package/dist/v2/components/CommandPalette.js +138 -225
- package/dist/v2/components/CommandPalette.js.map +1 -1
- package/dist/v2/components/ConfirmDialog.js +46 -56
- package/dist/v2/components/ConfirmDialog.js.map +1 -1
- package/dist/v2/components/DatePicker.js +81 -86
- package/dist/v2/components/DatePicker.js.map +1 -1
- package/dist/v2/components/DateRangePicker.js +77 -87
- package/dist/v2/components/DateRangePicker.js.map +1 -1
- package/dist/v2/components/DateTimePicker.js +84 -91
- package/dist/v2/components/DateTimePicker.js.map +1 -1
- package/dist/v2/components/Drawer.d.ts.map +1 -1
- package/dist/v2/components/Drawer.js +93 -88
- package/dist/v2/components/Drawer.js.map +1 -1
- package/dist/v2/components/Dropzone.js +150 -196
- package/dist/v2/components/Dropzone.js.map +1 -1
- package/dist/v2/components/EmptyState.js +18 -20
- package/dist/v2/components/EmptyState.js.map +1 -1
- package/dist/v2/components/FavoriteToggle.js +28 -39
- package/dist/v2/components/FavoriteToggle.js.map +1 -1
- package/dist/v2/components/Field.d.ts +62 -4
- package/dist/v2/components/Field.d.ts.map +1 -1
- package/dist/v2/components/Field.js +169 -70
- package/dist/v2/components/Field.js.map +1 -1
- package/dist/v2/components/FieldError.js +18 -21
- package/dist/v2/components/FieldError.js.map +1 -1
- package/dist/v2/components/FieldHelp.js +40 -60
- package/dist/v2/components/FieldHelp.js.map +1 -1
- package/dist/v2/components/FileCard.js +27 -31
- package/dist/v2/components/FileCard.js.map +1 -1
- package/dist/v2/components/FilterTab.js +30 -38
- package/dist/v2/components/FilterTab.js.map +1 -1
- package/dist/v2/components/ForbiddenPage.d.ts +25 -1
- package/dist/v2/components/ForbiddenPage.d.ts.map +1 -1
- package/dist/v2/components/ForbiddenPage.js +37 -17
- package/dist/v2/components/ForbiddenPage.js.map +1 -1
- package/dist/v2/components/FormGrid.js +53 -59
- package/dist/v2/components/FormGrid.js.map +1 -1
- package/dist/v2/components/FormikDisplay.d.ts +50 -1
- package/dist/v2/components/FormikDisplay.d.ts.map +1 -1
- package/dist/v2/components/FormikDisplay.js +108 -33
- package/dist/v2/components/FormikDisplay.js.map +1 -1
- package/dist/v2/components/Input.d.ts +40 -0
- package/dist/v2/components/Input.d.ts.map +1 -1
- package/dist/v2/components/Input.js +81 -41
- package/dist/v2/components/Input.js.map +1 -1
- package/dist/v2/components/KPICard.js +57 -67
- package/dist/v2/components/KPICard.js.map +1 -1
- package/dist/v2/components/KPIStrip.js +16 -22
- package/dist/v2/components/KPIStrip.js.map +1 -1
- package/dist/v2/components/KV.js +25 -31
- package/dist/v2/components/KV.js.map +1 -1
- package/dist/v2/components/KVGrid.js +19 -26
- package/dist/v2/components/KVGrid.js.map +1 -1
- package/dist/v2/components/Layout.js +91 -120
- package/dist/v2/components/Layout.js.map +1 -1
- package/dist/v2/components/MobileRowCard.js +79 -91
- package/dist/v2/components/MobileRowCard.js.map +1 -1
- package/dist/v2/components/Modal.js +61 -69
- package/dist/v2/components/Modal.js.map +1 -1
- package/dist/v2/components/NetworkErrorPage.d.ts +19 -1
- package/dist/v2/components/NetworkErrorPage.d.ts.map +1 -1
- package/dist/v2/components/NetworkErrorPage.js +38 -21
- package/dist/v2/components/NetworkErrorPage.js.map +1 -1
- package/dist/v2/components/NotFoundPage.d.ts +17 -1
- package/dist/v2/components/NotFoundPage.d.ts.map +1 -1
- package/dist/v2/components/NotFoundPage.js +37 -18
- package/dist/v2/components/NotFoundPage.js.map +1 -1
- package/dist/v2/components/NumberInput.js +88 -118
- package/dist/v2/components/NumberInput.js.map +1 -1
- package/dist/v2/components/OverflowMenu.js +38 -56
- package/dist/v2/components/OverflowMenu.js.map +1 -1
- package/dist/v2/components/PdfViewer.js +34 -45
- package/dist/v2/components/PdfViewer.js.map +1 -1
- package/dist/v2/components/ProgressBar.js +42 -49
- package/dist/v2/components/ProgressBar.js.map +1 -1
- package/dist/v2/components/Radio.js +59 -67
- package/dist/v2/components/Radio.js.map +1 -1
- package/dist/v2/components/SectionErrorBoundary.js +90 -135
- package/dist/v2/components/SectionErrorBoundary.js.map +1 -1
- package/dist/v2/components/SectionHeader.js +34 -41
- package/dist/v2/components/SectionHeader.js.map +1 -1
- package/dist/v2/components/Segmented.js +69 -93
- package/dist/v2/components/Segmented.js.map +1 -1
- package/dist/v2/components/Select.d.ts +26 -2
- package/dist/v2/components/Select.d.ts.map +1 -1
- package/dist/v2/components/Select.js +120 -155
- package/dist/v2/components/Select.js.map +1 -1
- package/dist/v2/components/ServerErrorPage.d.ts +27 -1
- package/dist/v2/components/ServerErrorPage.d.ts.map +1 -1
- package/dist/v2/components/ServerErrorPage.js +37 -20
- package/dist/v2/components/ServerErrorPage.js.map +1 -1
- package/dist/v2/components/Skeleton.js +86 -100
- package/dist/v2/components/Skeleton.js.map +1 -1
- package/dist/v2/components/SkipLink.js +9 -12
- package/dist/v2/components/SkipLink.js.map +1 -1
- package/dist/v2/components/Spinner.js +16 -25
- package/dist/v2/components/Spinner.js.map +1 -1
- package/dist/v2/components/Status.js +18 -29
- package/dist/v2/components/Status.js.map +1 -1
- package/dist/v2/components/Stepper.js +80 -82
- package/dist/v2/components/Stepper.js.map +1 -1
- package/dist/v2/components/Surface.js +34 -49
- package/dist/v2/components/Surface.js.map +1 -1
- package/dist/v2/components/Switch.js +29 -37
- package/dist/v2/components/Switch.js.map +1 -1
- package/dist/v2/components/TabPanel.d.ts +17 -0
- package/dist/v2/components/TabPanel.d.ts.map +1 -0
- package/dist/v2/components/TabPanel.js +90 -0
- package/dist/v2/components/TabPanel.js.map +1 -0
- package/dist/v2/components/Tabs.d.ts +25 -0
- package/dist/v2/components/Tabs.d.ts.map +1 -1
- package/dist/v2/components/Tabs.js +53 -29
- package/dist/v2/components/Tabs.js.map +1 -1
- package/dist/v2/components/TelInput.js +80 -115
- package/dist/v2/components/TelInput.js.map +1 -1
- package/dist/v2/components/Textarea.js +26 -35
- package/dist/v2/components/Textarea.js.map +1 -1
- package/dist/v2/components/TimePicker.js +62 -74
- package/dist/v2/components/TimePicker.js.map +1 -1
- package/dist/v2/components/Toast.js +119 -174
- package/dist/v2/components/Toast.js.map +1 -1
- package/dist/v2/components/Tooltip.js +23 -38
- package/dist/v2/components/Tooltip.js.map +1 -1
- package/dist/v2/components/_ErrorPageBody.js +15 -16
- package/dist/v2/components/_ErrorPageBody.js.map +1 -1
- package/dist/v2/components/_pickerShared.js +5 -5
- package/dist/v2/components/_pickerShared.js.map +1 -1
- package/dist/v2/components/index.d.ts +40 -1
- package/dist/v2/components/index.d.ts.map +1 -1
- package/dist/v2/components/index.js +153 -136
- package/dist/v2/components/index.js.map +1 -1
- package/dist/v2/hooks/index.d.ts +65 -0
- package/dist/v2/hooks/index.d.ts.map +1 -1
- package/dist/v2/hooks/index.js +63 -24
- package/dist/v2/hooks/index.js.map +1 -1
- package/dist/v2/hooks/useAppliedFilters.d.ts +102 -0
- package/dist/v2/hooks/useAppliedFilters.d.ts.map +1 -0
- package/dist/v2/hooks/useAppliedFilters.js +117 -0
- package/dist/v2/hooks/useAppliedFilters.js.map +1 -0
- package/dist/v2/hooks/useDebouncedCallback.d.ts +64 -0
- package/dist/v2/hooks/useDebouncedCallback.d.ts.map +1 -0
- package/dist/v2/hooks/useDebouncedCallback.js +87 -0
- package/dist/v2/hooks/useDebouncedCallback.js.map +1 -0
- package/dist/v2/hooks/useDelayedFlag.js +6 -20
- package/dist/v2/hooks/useDelayedFlag.js.map +1 -1
- package/dist/v2/hooks/useDensity.d.ts.map +1 -1
- package/dist/v2/hooks/useDensity.js +14 -18
- package/dist/v2/hooks/useDensity.js.map +1 -1
- package/dist/v2/hooks/useFocusFirstError.js +26 -34
- package/dist/v2/hooks/useFocusFirstError.js.map +1 -1
- package/dist/v2/hooks/useFocusOnRouteChange.d.ts +65 -0
- package/dist/v2/hooks/useFocusOnRouteChange.d.ts.map +1 -0
- package/dist/v2/hooks/useFocusOnRouteChange.js +88 -0
- package/dist/v2/hooks/useFocusOnRouteChange.js.map +1 -0
- package/dist/v2/hooks/useFocusTrap.js +20 -24
- package/dist/v2/hooks/useFocusTrap.js.map +1 -1
- package/dist/v2/hooks/useFormAutoSave.d.ts +4 -4
- package/dist/v2/hooks/useFormAutoSave.d.ts.map +1 -1
- package/dist/v2/hooks/useFormAutoSave.js +39 -54
- package/dist/v2/hooks/useFormAutoSave.js.map +1 -1
- package/dist/v2/hooks/useFormCompletionProgress.d.ts +1 -1
- package/dist/v2/hooks/useFormCompletionProgress.d.ts.map +1 -1
- package/dist/v2/hooks/useFormCompletionProgress.js +33 -52
- package/dist/v2/hooks/useFormCompletionProgress.js.map +1 -1
- package/dist/v2/hooks/useKeyboardShortcuts.d.ts +25 -0
- package/dist/v2/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/dist/v2/hooks/useKeyboardShortcuts.js +132 -0
- package/dist/v2/hooks/useKeyboardShortcuts.js.map +1 -0
- package/dist/v2/hooks/usePrefersReducedMotion.d.ts +56 -0
- package/dist/v2/hooks/usePrefersReducedMotion.d.ts.map +1 -0
- package/dist/v2/hooks/usePrefersReducedMotion.js +105 -0
- package/dist/v2/hooks/usePrefersReducedMotion.js.map +1 -0
- package/dist/v2/hooks/useResolvedDensity.js +5 -13
- package/dist/v2/hooks/useResolvedDensity.js.map +1 -1
- package/dist/v2/hooks/useSortedRows.js +4 -6
- package/dist/v2/hooks/useSortedRows.js.map +1 -1
- package/dist/v2/hooks/useTabLoading.js +7 -22
- package/dist/v2/hooks/useTabLoading.js.map +1 -1
- package/dist/v2/index.js +143 -145
- package/dist/v2/index.js.map +1 -1
- package/dist/v2/modalContext.js +2 -2
- package/dist/v2/modalContext.js.map +1 -1
- package/dist/v2/models/favorite.d.ts +8 -9
- package/dist/v2/models/favorite.d.ts.map +1 -1
- package/dist/v2/models/favorite.js.map +1 -1
- package/dist/v2/models/index.js +4 -4
- package/dist/v2/models/index.js.map +1 -1
- package/dist/v2/models/personalization.d.ts +44 -48
- package/dist/v2/models/personalization.d.ts.map +1 -1
- package/dist/v2/models/personalization.js.map +1 -1
- package/dist/v2/models/referentiel.d.ts +32 -50
- package/dist/v2/models/referentiel.d.ts.map +1 -1
- package/dist/v2/models/referentiel.js.map +1 -1
- package/dist/v2/models/savedFilter.d.ts +8 -17
- package/dist/v2/models/savedFilter.d.ts.map +1 -1
- package/dist/v2/models/savedFilter.js.map +1 -1
- package/dist/v2/patterns/ActionBar.js +152 -187
- package/dist/v2/patterns/ActionBar.js.map +1 -1
- package/dist/v2/patterns/AppMain.d.ts +109 -0
- package/dist/v2/patterns/AppMain.d.ts.map +1 -0
- package/dist/v2/patterns/AppMain.js +115 -0
- package/dist/v2/patterns/AppMain.js.map +1 -0
- package/dist/v2/patterns/BulkActionBar.js +40 -42
- package/dist/v2/patterns/BulkActionBar.js.map +1 -1
- package/dist/v2/patterns/ChartFigure.d.ts +124 -0
- package/dist/v2/patterns/ChartFigure.d.ts.map +1 -0
- package/dist/v2/patterns/ChartFigure.js +159 -0
- package/dist/v2/patterns/ChartFigure.js.map +1 -0
- package/dist/v2/patterns/CollapsibleDataGrid.js +138 -174
- package/dist/v2/patterns/CollapsibleDataGrid.js.map +1 -1
- package/dist/v2/patterns/ColumnsToggle.js +60 -94
- package/dist/v2/patterns/ColumnsToggle.js.map +1 -1
- package/dist/v2/patterns/DataGrid.d.ts.map +1 -1
- package/dist/v2/patterns/DataGrid.js +262 -297
- package/dist/v2/patterns/DataGrid.js.map +1 -1
- package/dist/v2/patterns/DataGridSettingsMenu.d.ts +12 -0
- package/dist/v2/patterns/DataGridSettingsMenu.d.ts.map +1 -1
- package/dist/v2/patterns/DataGridSettingsMenu.js +104 -121
- package/dist/v2/patterns/DataGridSettingsMenu.js.map +1 -1
- package/dist/v2/patterns/DataGridToolbar.js +103 -106
- package/dist/v2/patterns/DataGridToolbar.js.map +1 -1
- package/dist/v2/patterns/DataGridVirtualized.js +179 -217
- package/dist/v2/patterns/DataGridVirtualized.js.map +1 -1
- package/dist/v2/patterns/DeleteResourceConfirmDialog.js +32 -35
- package/dist/v2/patterns/DeleteResourceConfirmDialog.js.map +1 -1
- package/dist/v2/patterns/DetailSplit.d.ts +87 -0
- package/dist/v2/patterns/DetailSplit.d.ts.map +1 -0
- package/dist/v2/patterns/DetailSplit.js +116 -0
- package/dist/v2/patterns/DetailSplit.js.map +1 -0
- package/dist/v2/patterns/FavoriteColumn.js +22 -23
- package/dist/v2/patterns/FavoriteColumn.js.map +1 -1
- package/dist/v2/patterns/FavoritesFilter.js +36 -44
- package/dist/v2/patterns/FavoritesFilter.js.map +1 -1
- package/dist/v2/patterns/FilterTabBar.d.ts +28 -0
- package/dist/v2/patterns/FilterTabBar.d.ts.map +1 -0
- package/dist/v2/patterns/FilterTabBar.js +120 -0
- package/dist/v2/patterns/FilterTabBar.js.map +1 -0
- package/dist/v2/patterns/FormErrorSummary.js +20 -23
- package/dist/v2/patterns/FormErrorSummary.js.map +1 -1
- package/dist/v2/patterns/FormPageShell.js +53 -50
- package/dist/v2/patterns/FormPageShell.js.map +1 -1
- package/dist/v2/patterns/FormSection.d.ts +8 -3
- package/dist/v2/patterns/FormSection.d.ts.map +1 -1
- package/dist/v2/patterns/FormSection.js +44 -51
- package/dist/v2/patterns/FormSection.js.map +1 -1
- package/dist/v2/patterns/FormikCheckbox.js +36 -45
- package/dist/v2/patterns/FormikCheckbox.js.map +1 -1
- package/dist/v2/patterns/FormikCheckboxGroup.d.ts +17 -1
- package/dist/v2/patterns/FormikCheckboxGroup.d.ts.map +1 -1
- package/dist/v2/patterns/FormikCheckboxGroup.js +62 -65
- package/dist/v2/patterns/FormikCheckboxGroup.js.map +1 -1
- package/dist/v2/patterns/FormikCombobox.js +55 -72
- package/dist/v2/patterns/FormikCombobox.js.map +1 -1
- package/dist/v2/patterns/FormikDatePicker.js +50 -64
- package/dist/v2/patterns/FormikDatePicker.js.map +1 -1
- package/dist/v2/patterns/FormikDateTimePicker.js +50 -64
- package/dist/v2/patterns/FormikDateTimePicker.js.map +1 -1
- package/dist/v2/patterns/FormikErrorFocus.js +25 -26
- package/dist/v2/patterns/FormikErrorFocus.js.map +1 -1
- package/dist/v2/patterns/FormikErrorSummary.d.ts +74 -0
- package/dist/v2/patterns/FormikErrorSummary.d.ts.map +1 -0
- package/dist/v2/patterns/FormikErrorSummary.js +97 -0
- package/dist/v2/patterns/FormikErrorSummary.js.map +1 -0
- package/dist/v2/patterns/FormikFile.d.ts +14 -1
- package/dist/v2/patterns/FormikFile.d.ts.map +1 -1
- package/dist/v2/patterns/FormikFile.js +99 -83
- package/dist/v2/patterns/FormikFile.js.map +1 -1
- package/dist/v2/patterns/FormikInput.js +45 -58
- package/dist/v2/patterns/FormikInput.js.map +1 -1
- package/dist/v2/patterns/FormikRadioGroup.js +45 -56
- package/dist/v2/patterns/FormikRadioGroup.js.map +1 -1
- package/dist/v2/patterns/FormikReferentielField.d.ts +12 -1
- package/dist/v2/patterns/FormikReferentielField.d.ts.map +1 -1
- package/dist/v2/patterns/FormikReferentielField.js +54 -64
- package/dist/v2/patterns/FormikReferentielField.js.map +1 -1
- package/dist/v2/patterns/FormikSelect.js +70 -92
- package/dist/v2/patterns/FormikSelect.js.map +1 -1
- package/dist/v2/patterns/FormikTextarea.js +35 -51
- package/dist/v2/patterns/FormikTextarea.js.map +1 -1
- package/dist/v2/patterns/KeyboardShortcutsHelp.js +60 -80
- package/dist/v2/patterns/KeyboardShortcutsHelp.js.map +1 -1
- package/dist/v2/patterns/NetworkErrorBanner.js +13 -16
- package/dist/v2/patterns/NetworkErrorBanner.js.map +1 -1
- package/dist/v2/patterns/PageContent.js +17 -20
- package/dist/v2/patterns/PageContent.js.map +1 -1
- package/dist/v2/patterns/PreviewDrawer.d.ts +49 -0
- package/dist/v2/patterns/PreviewDrawer.d.ts.map +1 -0
- package/dist/v2/patterns/PreviewDrawer.js +159 -0
- package/dist/v2/patterns/PreviewDrawer.js.map +1 -0
- package/dist/v2/patterns/ReferentielField.d.ts +86 -2
- package/dist/v2/patterns/ReferentielField.d.ts.map +1 -1
- package/dist/v2/patterns/ReferentielField.js +347 -327
- package/dist/v2/patterns/ReferentielField.js.map +1 -1
- package/dist/v2/patterns/RowFavoriteToggle.d.ts +6 -0
- package/dist/v2/patterns/RowFavoriteToggle.d.ts.map +1 -1
- package/dist/v2/patterns/RowFavoriteToggle.js +38 -30
- package/dist/v2/patterns/RowFavoriteToggle.js.map +1 -1
- package/dist/v2/patterns/SaveFilterDialog.js +50 -77
- package/dist/v2/patterns/SaveFilterDialog.js.map +1 -1
- package/dist/v2/patterns/SavedFiltersMenu.js +89 -107
- package/dist/v2/patterns/SavedFiltersMenu.js.map +1 -1
- package/dist/v2/patterns/SkeletonPageShell.js +122 -143
- package/dist/v2/patterns/SkeletonPageShell.js.map +1 -1
- package/dist/v2/patterns/SortableHeader.js +35 -57
- package/dist/v2/patterns/SortableHeader.js.map +1 -1
- package/dist/v2/patterns/Tour.js +121 -142
- package/dist/v2/patterns/Tour.js.map +1 -1
- package/dist/v2/patterns/_dataGridShared.d.ts.map +1 -1
- package/dist/v2/patterns/_dataGridShared.js +131 -147
- package/dist/v2/patterns/_dataGridShared.js.map +1 -1
- package/dist/v2/patterns/_pickerSerialisation.js +9 -10
- package/dist/v2/patterns/_pickerSerialisation.js.map +1 -1
- package/dist/v2/patterns/_sort.js +17 -33
- package/dist/v2/patterns/_sort.js.map +1 -1
- package/dist/v2/patterns/_useColumnReorder.js +124 -163
- package/dist/v2/patterns/_useColumnReorder.js.map +1 -1
- package/dist/v2/patterns/_useColumnResize.js +80 -99
- package/dist/v2/patterns/_useColumnResize.js.map +1 -1
- package/dist/v2/patterns/filterCriteria.d.ts +78 -0
- package/dist/v2/patterns/filterCriteria.d.ts.map +1 -0
- package/dist/v2/patterns/filterCriteria.js +110 -0
- package/dist/v2/patterns/filterCriteria.js.map +1 -0
- package/dist/v2/patterns/index.d.ts +160 -0
- package/dist/v2/patterns/index.d.ts.map +1 -1
- package/dist/v2/patterns/index.js +157 -79
- package/dist/v2/patterns/index.js.map +1 -1
- package/dist/v2/patterns/rowActions.d.ts +150 -0
- package/dist/v2/patterns/rowActions.d.ts.map +1 -0
- package/dist/v2/patterns/rowActions.js +232 -0
- package/dist/v2/patterns/rowActions.js.map +1 -0
- package/dist/v2/personalization/PersonalizationProvider.d.ts.map +1 -1
- package/dist/v2/personalization/PersonalizationProvider.js +57 -53
- package/dist/v2/personalization/PersonalizationProvider.js.map +1 -1
- package/dist/v2/personalization/adapters/_storageKey.js +5 -5
- package/dist/v2/personalization/adapters/_storageKey.js.map +1 -1
- package/dist/v2/personalization/adapters/createLocalStorageAdapter.js +25 -24
- package/dist/v2/personalization/adapters/createLocalStorageAdapter.js.map +1 -1
- package/dist/v2/personalization/adapters/createMemoryAdapter.js +14 -14
- package/dist/v2/personalization/adapters/createMemoryAdapter.js.map +1 -1
- package/dist/v2/personalization/adapters/index.js +5 -5
- package/dist/v2/personalization/adapters/index.js.map +1 -1
- package/dist/v2/personalization/capabilities/favorites.js +39 -62
- package/dist/v2/personalization/capabilities/favorites.js.map +1 -1
- package/dist/v2/personalization/capabilities/favoritesView.js +25 -37
- package/dist/v2/personalization/capabilities/favoritesView.js.map +1 -1
- package/dist/v2/personalization/capabilities/gridPreferences.js +31 -36
- package/dist/v2/personalization/capabilities/gridPreferences.js.map +1 -1
- package/dist/v2/personalization/capabilities/index.js +12 -12
- package/dist/v2/personalization/capabilities/reviveSavedCriteria.d.ts +88 -0
- package/dist/v2/personalization/capabilities/reviveSavedCriteria.d.ts.map +1 -0
- package/dist/v2/personalization/capabilities/reviveSavedCriteria.js +126 -0
- package/dist/v2/personalization/capabilities/reviveSavedCriteria.js.map +1 -0
- package/dist/v2/personalization/capabilities/savedFilters.js +93 -100
- package/dist/v2/personalization/capabilities/savedFilters.js.map +1 -1
- package/dist/v2/personalization/createPersonalizationStore.d.ts.map +1 -1
- package/dist/v2/personalization/createPersonalizationStore.js +81 -182
- package/dist/v2/personalization/createPersonalizationStore.js.map +1 -1
- package/dist/v2/personalization/index.d.ts +16 -0
- package/dist/v2/personalization/index.d.ts.map +1 -1
- package/dist/v2/personalization/index.js +30 -23
- package/dist/v2/personalization/index.js.map +1 -1
- package/dist/v2/personalization/personalizationContext.js +10 -12
- package/dist/v2/personalization/personalizationContext.js.map +1 -1
- package/dist/v2/personalization/schema.js +8 -9
- package/dist/v2/personalization/schema.js.map +1 -1
- package/dist/v2/referentiel/ReferentielProvider.js +31 -45
- package/dist/v2/referentiel/ReferentielProvider.js.map +1 -1
- package/dist/v2/referentiel/index.js +11 -13
- package/dist/v2/referentiel/index.js.map +1 -1
- package/dist/v2/referentiel/types.d.ts +105 -0
- package/dist/v2/referentiel/types.d.ts.map +1 -0
- package/dist/v2/referentiel/types.js +6 -0
- package/dist/v2/referentiel/types.js.map +1 -0
- package/dist/v2/referentiel/useReferentielClient.js +13 -16
- package/dist/v2/referentiel/useReferentielClient.js.map +1 -1
- package/dist/v2/referentiel/useReferentielOptions.d.ts +7 -17
- package/dist/v2/referentiel/useReferentielOptions.d.ts.map +1 -1
- package/dist/v2/referentiel/useReferentielOptions.js +63 -120
- package/dist/v2/referentiel/useReferentielOptions.js.map +1 -1
- package/dist/v2/referentiel/useReferentielSearch.d.ts +7 -48
- package/dist/v2/referentiel/useReferentielSearch.d.ts.map +1 -1
- package/dist/v2/referentiel/useReferentielSearch.js +40 -95
- package/dist/v2/referentiel/useReferentielSearch.js.map +1 -1
- package/dist/v2/theme/_brand.js +12 -26
- package/dist/v2/theme/_brand.js.map +1 -1
- package/dist/v2/theme/_brandSecondary.js +12 -26
- package/dist/v2/theme/_brandSecondary.js.map +1 -1
- package/dist/v2/theme/createPortnetTheme.js +41 -49
- package/dist/v2/theme/createPortnetTheme.js.map +1 -1
- package/dist/v2/theme/cssVariables.d.ts +3 -3
- package/dist/v2/theme/cssVariables.d.ts.map +1 -1
- package/dist/v2/theme/cssVariables.js +65 -70
- package/dist/v2/theme/cssVariables.js.map +1 -1
- package/dist/v2/theme/index.js +10 -10
- package/dist/v2/theme/index.js.map +1 -1
- package/dist/v2/tokens/breakpoints.js +16 -16
- package/dist/v2/tokens/breakpoints.js.map +1 -1
- package/dist/v2/tokens/chart.d.ts +103 -0
- package/dist/v2/tokens/chart.d.ts.map +1 -0
- package/dist/v2/tokens/chart.js +270 -0
- package/dist/v2/tokens/chart.js.map +1 -0
- package/dist/v2/tokens/colors.js +24 -24
- package/dist/v2/tokens/colors.js.map +1 -1
- package/dist/v2/tokens/density.d.ts +104 -0
- package/dist/v2/tokens/density.d.ts.map +1 -1
- package/dist/v2/tokens/density.js +67 -12
- package/dist/v2/tokens/density.js.map +1 -1
- package/dist/v2/tokens/index.d.ts +50 -1
- package/dist/v2/tokens/index.d.ts.map +1 -1
- package/dist/v2/tokens/index.js +116 -68
- package/dist/v2/tokens/index.js.map +1 -1
- package/dist/v2/tokens/motion.js +16 -22
- package/dist/v2/tokens/motion.js.map +1 -1
- package/dist/v2/tokens/radius.js +3 -3
- package/dist/v2/tokens/radius.js.map +1 -1
- package/dist/v2/tokens/shadows.js +8 -8
- package/dist/v2/tokens/shadows.js.map +1 -1
- package/dist/v2/tokens/spacing.js +4 -4
- package/dist/v2/tokens/spacing.js.map +1 -1
- package/dist/v2/tokens/state.js +3 -3
- package/dist/v2/tokens/state.js.map +1 -1
- package/dist/v2/tokens/statusPalette.js +21 -23
- package/dist/v2/tokens/statusPalette.js.map +1 -1
- package/dist/v2/tokens/tokens.json +6 -1
- package/dist/v2/tokens/typography.js +15 -15
- package/dist/v2/tokens/typography.js.map +1 -1
- package/dist/v2/tokens/zIndex.js +3 -3
- package/dist/v2/tokens/zIndex.js.map +1 -1
- package/dist/v2/types/datagrid.d.ts +9 -1
- package/dist/v2/types/datagrid.d.ts.map +1 -1
- package/dist/v2/types/datagrid.js.map +1 -1
- package/dist/v2/types/index.js +2 -2
- package/dist/v2/types/index.js.map +1 -1
- package/dist/v2/utils/apiError.js +16 -37
- package/dist/v2/utils/apiError.js.map +1 -1
- package/dist/v2/utils/contrast.js +31 -32
- package/dist/v2/utils/contrast.js.map +1 -1
- package/dist/v2/utils/cx.js +7 -27
- package/dist/v2/utils/cx.js.map +1 -1
- package/dist/v2/utils/fileDownload.js +25 -28
- package/dist/v2/utils/fileDownload.js.map +1 -1
- package/dist/v2/utils/fileValidation.d.ts +116 -0
- package/dist/v2/utils/fileValidation.d.ts.map +1 -0
- package/dist/v2/utils/fileValidation.js +220 -0
- package/dist/v2/utils/fileValidation.js.map +1 -0
- package/dist/v2/utils/fmtDate.d.ts +103 -0
- package/dist/v2/utils/fmtDate.d.ts.map +1 -0
- package/dist/v2/utils/fmtDate.js +119 -0
- package/dist/v2/utils/fmtDate.js.map +1 -0
- package/dist/v2/utils/fmtMoney.d.ts +3 -3
- package/dist/v2/utils/fmtMoney.d.ts.map +1 -1
- package/dist/v2/utils/fmtMoney.js +9 -11
- package/dist/v2/utils/fmtMoney.js.map +1 -1
- package/dist/v2/utils/formikErrors.d.ts +67 -0
- package/dist/v2/utils/formikErrors.d.ts.map +1 -0
- package/dist/v2/utils/formikErrors.js +85 -0
- package/dist/v2/utils/formikErrors.js.map +1 -0
- package/dist/v2/utils/index.d.ts +5 -0
- package/dist/v2/utils/index.d.ts.map +1 -1
- package/dist/v2/utils/index.js +67 -18
- package/dist/v2/utils/index.js.map +1 -1
- package/dist/v2/utils/mergeLabels.js +9 -14
- package/dist/v2/utils/mergeLabels.js.map +1 -1
- package/dist/v2/utils/networkStatus.js +14 -14
- package/dist/v2/utils/networkStatus.js.map +1 -1
- package/package.json +26 -9
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fileValidation — is this file allowed to be uploaded?
|
|
3
|
+
*
|
|
4
|
+
* const POLICY = { extensions: ["pdf", "png", "jpg", "jpeg", "doc", "docx"] };
|
|
5
|
+
*
|
|
6
|
+
* const rejection = getFileRejection(file, POLICY);
|
|
7
|
+
* if (rejection) toast(rejection.message, "error");
|
|
8
|
+
*
|
|
9
|
+
* <Dropzone accept={toAcceptAttribute(POLICY.extensions)} … />
|
|
10
|
+
*
|
|
11
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
* WHY THIS BELONGS IN THE LIBRARY (capability gap G-52)
|
|
13
|
+
*
|
|
14
|
+
* `Dropzone` takes an `accept` attribute and reports `DropzoneRejection`, but it
|
|
15
|
+
* validates nothing: the browser's `accept` is a FILE-PICKER FILTER, not a
|
|
16
|
+
* control. It is trivially bypassed — drag and drop ignores it, and so does
|
|
17
|
+
* "All files" in the picker on most platforms. So the library asked every host
|
|
18
|
+
* to decide, itself, whether a dropped file is acceptable, and every host wrote:
|
|
19
|
+
*
|
|
20
|
+
* - an extension allow-list (business policy — rightly theirs), AND
|
|
21
|
+
* - a deny-list of executables and scripts, AND
|
|
22
|
+
* - an extension↔MIME cross-check with its browser tolerances.
|
|
23
|
+
*
|
|
24
|
+
* The last two are NOT business policy. They are one security decision, and a
|
|
25
|
+
* security decision copied into every module is a security decision that WILL
|
|
26
|
+
* drift: the day a file type has to be added to the deny-list, nobody can say
|
|
27
|
+
* which of the fifteen GU modules received it. Worse, divergence here is
|
|
28
|
+
* SILENT — a module missing an entry looks exactly like a module that has it,
|
|
29
|
+
* until something gets uploaded.
|
|
30
|
+
*
|
|
31
|
+
* So the split this file draws: the HOST owns which extensions its business
|
|
32
|
+
* accepts; the LIBRARY owns the executable deny-list and the MIME cross-check.
|
|
33
|
+
*
|
|
34
|
+
* Raised from `autorisation-admis-pour-conforme-fe` (Area 5), which carried a
|
|
35
|
+
* 21-entry executable deny-list and a six-extension MIME table locally.
|
|
36
|
+
*
|
|
37
|
+
* NOT A SUBSTITUTE FOR SERVER-SIDE VALIDATION, and this must stay written down:
|
|
38
|
+
* everything here runs in a browser the user controls. Its purpose is to give a
|
|
39
|
+
* CLEAR, IMMEDIATE reason (R-4.1, R-4.4) instead of a server rejection after a
|
|
40
|
+
* full upload. The back-end remains the authority.
|
|
41
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
42
|
+
*/
|
|
43
|
+
/** Why a file was refused. `reason` is for branching and logs, not for display. */
|
|
44
|
+
export type FileRejectionReason = "executable" | "extension" | "mime";
|
|
45
|
+
export interface FileRejection {
|
|
46
|
+
reason: FileRejectionReason;
|
|
47
|
+
/** Ready to render (French, Charter §09.3 — what, and what is accepted). */
|
|
48
|
+
message: string;
|
|
49
|
+
}
|
|
50
|
+
export interface FileAcceptPolicy {
|
|
51
|
+
/**
|
|
52
|
+
* Extensions the HOST's business accepts, without a leading dot,
|
|
53
|
+
* case-insensitive. This is the only part of the decision that belongs to the
|
|
54
|
+
* host — an empty list accepts nothing, which is a programming error rather
|
|
55
|
+
* than a policy, so it is treated as "refuse everything" and not as "allow".
|
|
56
|
+
*/
|
|
57
|
+
extensions: readonly string[];
|
|
58
|
+
/** Overrides for the default messages. Keep them in French, verb + object. */
|
|
59
|
+
labels?: {
|
|
60
|
+
executable?: string | undefined;
|
|
61
|
+
type?: string | undefined;
|
|
62
|
+
} | undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Human list of the accepted types — "PDF, PNG, JPG, JPEG, DOC, DOCX."
|
|
66
|
+
*
|
|
67
|
+
* Order is the host's: the list is read by a person, and a host lists its most
|
|
68
|
+
* common format first for a reason. Sorting it here would silently reorder
|
|
69
|
+
* copy the host wrote deliberately.
|
|
70
|
+
*/
|
|
71
|
+
export declare function describeAcceptedTypes(extensions: readonly string[]): string;
|
|
72
|
+
/**
|
|
73
|
+
* The `accept` attribute for an input or `Dropzone` — ".pdf,.png,.jpg".
|
|
74
|
+
*
|
|
75
|
+
* A picker filter, never a control: see the note on server-side validation in
|
|
76
|
+
* the file header.
|
|
77
|
+
*/
|
|
78
|
+
export declare function toAcceptAttribute(extensions: readonly string[]): string;
|
|
79
|
+
/**
|
|
80
|
+
* Is this an executable, a script or an installer?
|
|
81
|
+
*
|
|
82
|
+
* Exported on its own because a host may want to refuse those EARLIER than its
|
|
83
|
+
* own policy check — on a bulk drop, for instance, where one dangerous file
|
|
84
|
+
* should stop the whole batch rather than be listed among type mismatches.
|
|
85
|
+
*
|
|
86
|
+
* Permissive parameter type on purpose: callers routinely pass an item pulled
|
|
87
|
+
* out of a `FileList` without having checked it.
|
|
88
|
+
*/
|
|
89
|
+
export declare function isForbiddenExecutable(file?: File | null | undefined): boolean;
|
|
90
|
+
/** Does the file satisfy `policy` (and the library's own deny-list)? */
|
|
91
|
+
export declare function isAcceptedFile(file: File | null | undefined, policy: FileAcceptPolicy): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Why this file cannot be uploaded, or `null` when it can.
|
|
94
|
+
*
|
|
95
|
+
* Order of checks is load-bearing:
|
|
96
|
+
* 1. executable / script / installer — named as such;
|
|
97
|
+
* 2. extension against the host's allow-list;
|
|
98
|
+
* 3. reported MIME type against the extension.
|
|
99
|
+
*
|
|
100
|
+
* MIME RULES, both deliberate: an EMPTY type is accepted (some browsers report
|
|
101
|
+
* none, and the extension has just been checked), and `application/octet-stream`
|
|
102
|
+
* is accepted for the extensions listed in `UNRELIABLE_MIME_EXTENSIONS`. An
|
|
103
|
+
* extension with no entry in the MIME table is accepted on its extension alone
|
|
104
|
+
* — the table is a cross-check, not a second allow-list, and a host adding a
|
|
105
|
+
* format to its policy must not have it refused by a table it cannot see.
|
|
106
|
+
*/
|
|
107
|
+
export declare function getFileRejection(file: File | null | undefined, policy: FileAcceptPolicy): FileRejection | null;
|
|
108
|
+
declare const fileValidationApi: {
|
|
109
|
+
isForbiddenExecutable: typeof isForbiddenExecutable;
|
|
110
|
+
isAcceptedFile: typeof isAcceptedFile;
|
|
111
|
+
getFileRejection: typeof getFileRejection;
|
|
112
|
+
describeAcceptedTypes: typeof describeAcceptedTypes;
|
|
113
|
+
toAcceptAttribute: typeof toAcceptAttribute;
|
|
114
|
+
};
|
|
115
|
+
export default fileValidationApi;
|
|
116
|
+
//# sourceMappingURL=fileValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileValidation.d.ts","sourceRoot":"","sources":["../../../src/lib/v2/utils/fileValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAwEH,mFAAmF;AACnF,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,WAAW,GAAG,MAAM,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,MAAM,CAAC,EACH;QACE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B,GACD,SAAS,CAAC;CACf;AAeD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG7E;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAC7B,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAET;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAC7B,MAAM,EAAE,gBAAgB,GACvB,aAAa,GAAG,IAAI,CA8BtB;AAED,QAAA,MAAM,iBAAiB;;;;;;CAMtB,CAAC;AACF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
exports.describeAcceptedTypes = describeAcceptedTypes;
|
|
8
|
+
exports.getFileRejection = getFileRejection;
|
|
9
|
+
exports.isAcceptedFile = isAcceptedFile;
|
|
10
|
+
exports.isForbiddenExecutable = isForbiddenExecutable;
|
|
11
|
+
exports.toAcceptAttribute = toAcceptAttribute;
|
|
12
|
+
/**
|
|
13
|
+
* fileValidation — is this file allowed to be uploaded?
|
|
14
|
+
*
|
|
15
|
+
* const POLICY = { extensions: ["pdf", "png", "jpg", "jpeg", "doc", "docx"] };
|
|
16
|
+
*
|
|
17
|
+
* const rejection = getFileRejection(file, POLICY);
|
|
18
|
+
* if (rejection) toast(rejection.message, "error");
|
|
19
|
+
*
|
|
20
|
+
* <Dropzone accept={toAcceptAttribute(POLICY.extensions)} … />
|
|
21
|
+
*
|
|
22
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
* WHY THIS BELONGS IN THE LIBRARY (capability gap G-52)
|
|
24
|
+
*
|
|
25
|
+
* `Dropzone` takes an `accept` attribute and reports `DropzoneRejection`, but it
|
|
26
|
+
* validates nothing: the browser's `accept` is a FILE-PICKER FILTER, not a
|
|
27
|
+
* control. It is trivially bypassed — drag and drop ignores it, and so does
|
|
28
|
+
* "All files" in the picker on most platforms. So the library asked every host
|
|
29
|
+
* to decide, itself, whether a dropped file is acceptable, and every host wrote:
|
|
30
|
+
*
|
|
31
|
+
* - an extension allow-list (business policy — rightly theirs), AND
|
|
32
|
+
* - a deny-list of executables and scripts, AND
|
|
33
|
+
* - an extension↔MIME cross-check with its browser tolerances.
|
|
34
|
+
*
|
|
35
|
+
* The last two are NOT business policy. They are one security decision, and a
|
|
36
|
+
* security decision copied into every module is a security decision that WILL
|
|
37
|
+
* drift: the day a file type has to be added to the deny-list, nobody can say
|
|
38
|
+
* which of the fifteen GU modules received it. Worse, divergence here is
|
|
39
|
+
* SILENT — a module missing an entry looks exactly like a module that has it,
|
|
40
|
+
* until something gets uploaded.
|
|
41
|
+
*
|
|
42
|
+
* So the split this file draws: the HOST owns which extensions its business
|
|
43
|
+
* accepts; the LIBRARY owns the executable deny-list and the MIME cross-check.
|
|
44
|
+
*
|
|
45
|
+
* Raised from `autorisation-admis-pour-conforme-fe` (Area 5), which carried a
|
|
46
|
+
* 21-entry executable deny-list and a six-extension MIME table locally.
|
|
47
|
+
*
|
|
48
|
+
* NOT A SUBSTITUTE FOR SERVER-SIDE VALIDATION, and this must stay written down:
|
|
49
|
+
* everything here runs in a browser the user controls. Its purpose is to give a
|
|
50
|
+
* CLEAR, IMMEDIATE reason (R-4.1, R-4.4) instead of a server rejection after a
|
|
51
|
+
* full upload. The back-end remains the authority.
|
|
52
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Executables, scripts and installers — refused whatever the host's policy says.
|
|
57
|
+
*
|
|
58
|
+
* Checked FIRST, and the order carries meaning: a `.exe` gets a message naming
|
|
59
|
+
* it as a dangerous file, not a vague "unsupported type", because those are not
|
|
60
|
+
* the same information for the person at the screen.
|
|
61
|
+
*
|
|
62
|
+
* Windows-centric because GU workstations are: PE binaries, the cmd/PowerShell
|
|
63
|
+
* script families, installer packages, and the HTML-application and
|
|
64
|
+
* control-panel shims that are executable despite innocuous extensions.
|
|
65
|
+
*/
|
|
66
|
+
const EXECUTABLE_EXTENSIONS = new Set(["exe", "dll", "bat", "cmd", "com", "pif", "scr", "msi", "msu", "msp", "vbs", "vbe", "jse", "wsf", "wsh", "ps1", "psm1", "psc1", "cpl", "msc", "hta"]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Accepted MIME types per extension.
|
|
70
|
+
*
|
|
71
|
+
* DELIBERATELY NOT `getMimeType` from ./fileDownload, though both map
|
|
72
|
+
* extensions to MIME types. That one answers "what type should I stamp on this
|
|
73
|
+
* Blob" — ONE canonical value. This one answers "what types may a browser
|
|
74
|
+
* plausibly report for this extension" — a SET, including variants no canonical
|
|
75
|
+
* table would contain (`image/jpg` is not a registered type, and browsers send
|
|
76
|
+
* it anyway). Collapsing the two would reject valid files.
|
|
77
|
+
*/
|
|
78
|
+
const MIME_BY_EXTENSION = Object.freeze({
|
|
79
|
+
pdf: ["application/pdf"],
|
|
80
|
+
png: ["image/png"],
|
|
81
|
+
jpg: ["image/jpeg", "image/jpg"],
|
|
82
|
+
jpeg: ["image/jpeg", "image/jpg"],
|
|
83
|
+
gif: ["image/gif"],
|
|
84
|
+
webp: ["image/webp"],
|
|
85
|
+
tif: ["image/tiff"],
|
|
86
|
+
tiff: ["image/tiff"],
|
|
87
|
+
txt: ["text/plain"],
|
|
88
|
+
csv: ["text/csv", "application/csv", "text/plain"],
|
|
89
|
+
doc: ["application/msword"],
|
|
90
|
+
docx: ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
|
|
91
|
+
xls: ["application/vnd.ms-excel"],
|
|
92
|
+
xlsx: ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
|
|
93
|
+
ppt: ["application/vnd.ms-powerpoint"],
|
|
94
|
+
pptx: ["application/vnd.openxmlformats-officedocument.presentationml.presentation"]
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Extensions whose reported MIME type cannot be trusted, so
|
|
99
|
+
* `application/octet-stream` is tolerated for them.
|
|
100
|
+
*
|
|
101
|
+
* WITHOUT THIS TOLERANCE A LEGITIMATE `.docx` IS REFUSED on some machines —
|
|
102
|
+
* Office documents are frequently reported as `application/octet-stream`
|
|
103
|
+
* depending on browser and OS, and the refusal would be INTERMITTENT, which is
|
|
104
|
+
* the hardest kind to diagnose from a support ticket. The extension has already
|
|
105
|
+
* been checked against the host's allow-list at that point, so the tolerance
|
|
106
|
+
* does not widen what is accepted, only what is believed.
|
|
107
|
+
*/
|
|
108
|
+
const UNRELIABLE_MIME_EXTENSIONS = new Set(["doc", "docx", "xls", "xlsx", "ppt", "pptx", "csv"]);
|
|
109
|
+
|
|
110
|
+
/** Why a file was refused. `reason` is for branching and logs, not for display. */
|
|
111
|
+
|
|
112
|
+
const DEFAULT_EXECUTABLE_MESSAGE = "Les fichiers exécutables, scripts et installeurs ne sont pas autorisés.";
|
|
113
|
+
|
|
114
|
+
/** Lowercased extension of a file name, or `""` when there is none. */
|
|
115
|
+
const extensionOf = fileName => {
|
|
116
|
+
if (!fileName) return "";
|
|
117
|
+
const parts = fileName.split(".");
|
|
118
|
+
/* A name with no dot has no extension: "rapport" must not be read as having
|
|
119
|
+
extension "rapport", which a bare `pop()` would do. */
|
|
120
|
+
if (parts.length < 2) return "";
|
|
121
|
+
return (parts[parts.length - 1] ?? "").toLowerCase();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Human list of the accepted types — "PDF, PNG, JPG, JPEG, DOC, DOCX."
|
|
126
|
+
*
|
|
127
|
+
* Order is the host's: the list is read by a person, and a host lists its most
|
|
128
|
+
* common format first for a reason. Sorting it here would silently reorder
|
|
129
|
+
* copy the host wrote deliberately.
|
|
130
|
+
*/
|
|
131
|
+
function describeAcceptedTypes(extensions) {
|
|
132
|
+
return `${extensions.map(ext => ext.toUpperCase()).join(", ")}.`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The `accept` attribute for an input or `Dropzone` — ".pdf,.png,.jpg".
|
|
137
|
+
*
|
|
138
|
+
* A picker filter, never a control: see the note on server-side validation in
|
|
139
|
+
* the file header.
|
|
140
|
+
*/
|
|
141
|
+
function toAcceptAttribute(extensions) {
|
|
142
|
+
return extensions.map(ext => `.${ext.toLowerCase()}`).join(",");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Is this an executable, a script or an installer?
|
|
147
|
+
*
|
|
148
|
+
* Exported on its own because a host may want to refuse those EARLIER than its
|
|
149
|
+
* own policy check — on a bulk drop, for instance, where one dangerous file
|
|
150
|
+
* should stop the whole batch rather than be listed among type mismatches.
|
|
151
|
+
*
|
|
152
|
+
* Permissive parameter type on purpose: callers routinely pass an item pulled
|
|
153
|
+
* out of a `FileList` without having checked it.
|
|
154
|
+
*/
|
|
155
|
+
function isForbiddenExecutable(file) {
|
|
156
|
+
const ext = extensionOf(file?.name);
|
|
157
|
+
return ext !== "" && EXECUTABLE_EXTENSIONS.has(ext);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Does the file satisfy `policy` (and the library's own deny-list)? */
|
|
161
|
+
function isAcceptedFile(file, policy) {
|
|
162
|
+
return getFileRejection(file, policy) === null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Why this file cannot be uploaded, or `null` when it can.
|
|
167
|
+
*
|
|
168
|
+
* Order of checks is load-bearing:
|
|
169
|
+
* 1. executable / script / installer — named as such;
|
|
170
|
+
* 2. extension against the host's allow-list;
|
|
171
|
+
* 3. reported MIME type against the extension.
|
|
172
|
+
*
|
|
173
|
+
* MIME RULES, both deliberate: an EMPTY type is accepted (some browsers report
|
|
174
|
+
* none, and the extension has just been checked), and `application/octet-stream`
|
|
175
|
+
* is accepted for the extensions listed in `UNRELIABLE_MIME_EXTENSIONS`. An
|
|
176
|
+
* extension with no entry in the MIME table is accepted on its extension alone
|
|
177
|
+
* — the table is a cross-check, not a second allow-list, and a host adding a
|
|
178
|
+
* format to its policy must not have it refused by a table it cannot see.
|
|
179
|
+
*/
|
|
180
|
+
function getFileRejection(file, policy) {
|
|
181
|
+
const executableMessage = policy.labels?.executable ?? DEFAULT_EXECUTABLE_MESSAGE;
|
|
182
|
+
const typeMessage = policy.labels?.type ?? `Types autorisés : ${describeAcceptedTypes(policy.extensions)}`;
|
|
183
|
+
if (isForbiddenExecutable(file)) {
|
|
184
|
+
return {
|
|
185
|
+
reason: "executable",
|
|
186
|
+
message: executableMessage
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const ext = extensionOf(file?.name);
|
|
190
|
+
if (ext === "") return {
|
|
191
|
+
reason: "extension",
|
|
192
|
+
message: typeMessage
|
|
193
|
+
};
|
|
194
|
+
const accepted = policy.extensions.some(allowed => allowed.toLowerCase() === ext);
|
|
195
|
+
if (!accepted) return {
|
|
196
|
+
reason: "extension",
|
|
197
|
+
message: typeMessage
|
|
198
|
+
};
|
|
199
|
+
const mime = (file?.type ?? "").trim().toLowerCase();
|
|
200
|
+
if (mime === "") return null;
|
|
201
|
+
if (mime === "application/octet-stream" && UNRELIABLE_MIME_EXTENSIONS.has(ext)) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const expected = MIME_BY_EXTENSION[ext];
|
|
205
|
+
if (expected === undefined) return null;
|
|
206
|
+
if (expected.includes(mime)) return null;
|
|
207
|
+
return {
|
|
208
|
+
reason: "mime",
|
|
209
|
+
message: typeMessage
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const fileValidationApi = {
|
|
213
|
+
isForbiddenExecutable,
|
|
214
|
+
isAcceptedFile,
|
|
215
|
+
getFileRejection,
|
|
216
|
+
describeAcceptedTypes,
|
|
217
|
+
toAcceptAttribute
|
|
218
|
+
};
|
|
219
|
+
var _default = exports.default = fileValidationApi;
|
|
220
|
+
//# sourceMappingURL=fileValidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileValidation.js","names":["EXECUTABLE_EXTENSIONS","Set","MIME_BY_EXTENSION","Object","freeze","pdf","png","jpg","jpeg","gif","webp","tif","tiff","txt","csv","doc","docx","xls","xlsx","ppt","pptx","UNRELIABLE_MIME_EXTENSIONS","DEFAULT_EXECUTABLE_MESSAGE","extensionOf","fileName","parts","split","length","toLowerCase","describeAcceptedTypes","extensions","map","ext","toUpperCase","join","toAcceptAttribute","isForbiddenExecutable","file","name","has","isAcceptedFile","policy","getFileRejection","executableMessage","labels","executable","typeMessage","type","reason","message","accepted","some","allowed","mime","trim","expected","undefined","includes","fileValidationApi","_default","exports","default"],"sources":["../../../src/lib/v2/utils/fileValidation.ts"],"sourcesContent":["/**\r\n * fileValidation — is this file allowed to be uploaded?\r\n *\r\n * const POLICY = { extensions: [\"pdf\", \"png\", \"jpg\", \"jpeg\", \"doc\", \"docx\"] };\r\n *\r\n * const rejection = getFileRejection(file, POLICY);\r\n * if (rejection) toast(rejection.message, \"error\");\r\n *\r\n * <Dropzone accept={toAcceptAttribute(POLICY.extensions)} … />\r\n *\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n * WHY THIS BELONGS IN THE LIBRARY (capability gap G-52)\r\n *\r\n * `Dropzone` takes an `accept` attribute and reports `DropzoneRejection`, but it\r\n * validates nothing: the browser's `accept` is a FILE-PICKER FILTER, not a\r\n * control. It is trivially bypassed — drag and drop ignores it, and so does\r\n * \"All files\" in the picker on most platforms. So the library asked every host\r\n * to decide, itself, whether a dropped file is acceptable, and every host wrote:\r\n *\r\n * - an extension allow-list (business policy — rightly theirs), AND\r\n * - a deny-list of executables and scripts, AND\r\n * - an extension↔MIME cross-check with its browser tolerances.\r\n *\r\n * The last two are NOT business policy. They are one security decision, and a\r\n * security decision copied into every module is a security decision that WILL\r\n * drift: the day a file type has to be added to the deny-list, nobody can say\r\n * which of the fifteen GU modules received it. Worse, divergence here is\r\n * SILENT — a module missing an entry looks exactly like a module that has it,\r\n * until something gets uploaded.\r\n *\r\n * So the split this file draws: the HOST owns which extensions its business\r\n * accepts; the LIBRARY owns the executable deny-list and the MIME cross-check.\r\n *\r\n * Raised from `autorisation-admis-pour-conforme-fe` (Area 5), which carried a\r\n * 21-entry executable deny-list and a six-extension MIME table locally.\r\n *\r\n * NOT A SUBSTITUTE FOR SERVER-SIDE VALIDATION, and this must stay written down:\r\n * everything here runs in a browser the user controls. Its purpose is to give a\r\n * CLEAR, IMMEDIATE reason (R-4.1, R-4.4) instead of a server rejection after a\r\n * full upload. The back-end remains the authority.\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n */\r\n\r\n/**\r\n * Executables, scripts and installers — refused whatever the host's policy says.\r\n *\r\n * Checked FIRST, and the order carries meaning: a `.exe` gets a message naming\r\n * it as a dangerous file, not a vague \"unsupported type\", because those are not\r\n * the same information for the person at the screen.\r\n *\r\n * Windows-centric because GU workstations are: PE binaries, the cmd/PowerShell\r\n * script families, installer packages, and the HTML-application and\r\n * control-panel shims that are executable despite innocuous extensions.\r\n */\r\nconst EXECUTABLE_EXTENSIONS: ReadonlySet<string> = new Set([\r\n \"exe\", \"dll\", \"bat\", \"cmd\", \"com\", \"pif\", \"scr\",\r\n \"msi\", \"msu\", \"msp\",\r\n \"vbs\", \"vbe\", \"jse\", \"wsf\", \"wsh\",\r\n \"ps1\", \"psm1\", \"psc1\",\r\n \"cpl\", \"msc\", \"hta\",\r\n]);\r\n\r\n/**\r\n * Accepted MIME types per extension.\r\n *\r\n * DELIBERATELY NOT `getMimeType` from ./fileDownload, though both map\r\n * extensions to MIME types. That one answers \"what type should I stamp on this\r\n * Blob\" — ONE canonical value. This one answers \"what types may a browser\r\n * plausibly report for this extension\" — a SET, including variants no canonical\r\n * table would contain (`image/jpg` is not a registered type, and browsers send\r\n * it anyway). Collapsing the two would reject valid files.\r\n */\r\nconst MIME_BY_EXTENSION: Readonly<Record<string, readonly string[]>> =\r\n Object.freeze({\r\n pdf: [\"application/pdf\"],\r\n png: [\"image/png\"],\r\n jpg: [\"image/jpeg\", \"image/jpg\"],\r\n jpeg: [\"image/jpeg\", \"image/jpg\"],\r\n gif: [\"image/gif\"],\r\n webp: [\"image/webp\"],\r\n tif: [\"image/tiff\"],\r\n tiff: [\"image/tiff\"],\r\n txt: [\"text/plain\"],\r\n csv: [\"text/csv\", \"application/csv\", \"text/plain\"],\r\n doc: [\"application/msword\"],\r\n docx: [\r\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\r\n ],\r\n xls: [\"application/vnd.ms-excel\"],\r\n xlsx: [\r\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\r\n ],\r\n ppt: [\"application/vnd.ms-powerpoint\"],\r\n pptx: [\r\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\r\n ],\r\n });\r\n\r\n/**\r\n * Extensions whose reported MIME type cannot be trusted, so\r\n * `application/octet-stream` is tolerated for them.\r\n *\r\n * WITHOUT THIS TOLERANCE A LEGITIMATE `.docx` IS REFUSED on some machines —\r\n * Office documents are frequently reported as `application/octet-stream`\r\n * depending on browser and OS, and the refusal would be INTERMITTENT, which is\r\n * the hardest kind to diagnose from a support ticket. The extension has already\r\n * been checked against the host's allow-list at that point, so the tolerance\r\n * does not widen what is accepted, only what is believed.\r\n */\r\nconst UNRELIABLE_MIME_EXTENSIONS: ReadonlySet<string> = new Set([\r\n \"doc\", \"docx\", \"xls\", \"xlsx\", \"ppt\", \"pptx\", \"csv\",\r\n]);\r\n\r\n/** Why a file was refused. `reason` is for branching and logs, not for display. */\r\nexport type FileRejectionReason = \"executable\" | \"extension\" | \"mime\";\r\n\r\nexport interface FileRejection {\r\n reason: FileRejectionReason;\r\n /** Ready to render (French, Charter §09.3 — what, and what is accepted). */\r\n message: string;\r\n}\r\n\r\nexport interface FileAcceptPolicy {\r\n /**\r\n * Extensions the HOST's business accepts, without a leading dot,\r\n * case-insensitive. This is the only part of the decision that belongs to the\r\n * host — an empty list accepts nothing, which is a programming error rather\r\n * than a policy, so it is treated as \"refuse everything\" and not as \"allow\".\r\n */\r\n extensions: readonly string[];\r\n /** Overrides for the default messages. Keep them in French, verb + object. */\r\n labels?:\r\n | {\r\n executable?: string | undefined;\r\n type?: string | undefined;\r\n }\r\n | undefined;\r\n}\r\n\r\nconst DEFAULT_EXECUTABLE_MESSAGE =\r\n \"Les fichiers exécutables, scripts et installeurs ne sont pas autorisés.\";\r\n\r\n/** Lowercased extension of a file name, or `\"\"` when there is none. */\r\nconst extensionOf = (fileName: string | undefined): string => {\r\n if (!fileName) return \"\";\r\n const parts = fileName.split(\".\");\r\n /* A name with no dot has no extension: \"rapport\" must not be read as having\r\n extension \"rapport\", which a bare `pop()` would do. */\r\n if (parts.length < 2) return \"\";\r\n return (parts[parts.length - 1] ?? \"\").toLowerCase();\r\n};\r\n\r\n/**\r\n * Human list of the accepted types — \"PDF, PNG, JPG, JPEG, DOC, DOCX.\"\r\n *\r\n * Order is the host's: the list is read by a person, and a host lists its most\r\n * common format first for a reason. Sorting it here would silently reorder\r\n * copy the host wrote deliberately.\r\n */\r\nexport function describeAcceptedTypes(\r\n extensions: readonly string[]\r\n): string {\r\n return `${extensions.map((ext) => ext.toUpperCase()).join(\", \")}.`;\r\n}\r\n\r\n/**\r\n * The `accept` attribute for an input or `Dropzone` — \".pdf,.png,.jpg\".\r\n *\r\n * A picker filter, never a control: see the note on server-side validation in\r\n * the file header.\r\n */\r\nexport function toAcceptAttribute(extensions: readonly string[]): string {\r\n return extensions.map((ext) => `.${ext.toLowerCase()}`).join(\",\");\r\n}\r\n\r\n/**\r\n * Is this an executable, a script or an installer?\r\n *\r\n * Exported on its own because a host may want to refuse those EARLIER than its\r\n * own policy check — on a bulk drop, for instance, where one dangerous file\r\n * should stop the whole batch rather than be listed among type mismatches.\r\n *\r\n * Permissive parameter type on purpose: callers routinely pass an item pulled\r\n * out of a `FileList` without having checked it.\r\n */\r\nexport function isForbiddenExecutable(file?: File | null | undefined): boolean {\r\n const ext = extensionOf(file?.name);\r\n return ext !== \"\" && EXECUTABLE_EXTENSIONS.has(ext);\r\n}\r\n\r\n/** Does the file satisfy `policy` (and the library's own deny-list)? */\r\nexport function isAcceptedFile(\r\n file: File | null | undefined,\r\n policy: FileAcceptPolicy\r\n): boolean {\r\n return getFileRejection(file, policy) === null;\r\n}\r\n\r\n/**\r\n * Why this file cannot be uploaded, or `null` when it can.\r\n *\r\n * Order of checks is load-bearing:\r\n * 1. executable / script / installer — named as such;\r\n * 2. extension against the host's allow-list;\r\n * 3. reported MIME type against the extension.\r\n *\r\n * MIME RULES, both deliberate: an EMPTY type is accepted (some browsers report\r\n * none, and the extension has just been checked), and `application/octet-stream`\r\n * is accepted for the extensions listed in `UNRELIABLE_MIME_EXTENSIONS`. An\r\n * extension with no entry in the MIME table is accepted on its extension alone\r\n * — the table is a cross-check, not a second allow-list, and a host adding a\r\n * format to its policy must not have it refused by a table it cannot see.\r\n */\r\nexport function getFileRejection(\r\n file: File | null | undefined,\r\n policy: FileAcceptPolicy\r\n): FileRejection | null {\r\n const executableMessage =\r\n policy.labels?.executable ?? DEFAULT_EXECUTABLE_MESSAGE;\r\n const typeMessage =\r\n policy.labels?.type ??\r\n `Types autorisés : ${describeAcceptedTypes(policy.extensions)}`;\r\n\r\n if (isForbiddenExecutable(file)) {\r\n return { reason: \"executable\", message: executableMessage };\r\n }\r\n\r\n const ext = extensionOf(file?.name);\r\n if (ext === \"\") return { reason: \"extension\", message: typeMessage };\r\n\r\n const accepted = policy.extensions.some(\r\n (allowed) => allowed.toLowerCase() === ext\r\n );\r\n if (!accepted) return { reason: \"extension\", message: typeMessage };\r\n\r\n const mime = (file?.type ?? \"\").trim().toLowerCase();\r\n if (mime === \"\") return null;\r\n if (mime === \"application/octet-stream\" && UNRELIABLE_MIME_EXTENSIONS.has(ext)) {\r\n return null;\r\n }\r\n\r\n const expected = MIME_BY_EXTENSION[ext];\r\n if (expected === undefined) return null;\r\n if (expected.includes(mime)) return null;\r\n\r\n return { reason: \"mime\", message: typeMessage };\r\n}\r\n\r\nconst fileValidationApi = {\r\n isForbiddenExecutable,\r\n isAcceptedFile,\r\n getFileRejection,\r\n describeAcceptedTypes,\r\n toAcceptAttribute,\r\n};\r\nexport default fileValidationApi;\r\n"],"mappings":";;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,qBAA0C,GAAG,IAAIC,GAAG,CAAC,CACzD,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAC/C,KAAK,EAAE,KAAK,EAAE,KAAK,EACnB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EACjC,KAAK,EAAE,MAAM,EAAE,MAAM,EACrB,KAAK,EAAE,KAAK,EAAE,KAAK,CACpB,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,iBAA8D,GAClEC,MAAM,CAACC,MAAM,CAAC;EACZC,GAAG,EAAE,CAAC,iBAAiB,CAAC;EACxBC,GAAG,EAAE,CAAC,WAAW,CAAC;EAClBC,GAAG,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;EAChCC,IAAI,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;EACjCC,GAAG,EAAE,CAAC,WAAW,CAAC;EAClBC,IAAI,EAAE,CAAC,YAAY,CAAC;EACpBC,GAAG,EAAE,CAAC,YAAY,CAAC;EACnBC,IAAI,EAAE,CAAC,YAAY,CAAC;EACpBC,GAAG,EAAE,CAAC,YAAY,CAAC;EACnBC,GAAG,EAAE,CAAC,UAAU,EAAE,iBAAiB,EAAE,YAAY,CAAC;EAClDC,GAAG,EAAE,CAAC,oBAAoB,CAAC;EAC3BC,IAAI,EAAE,CACJ,yEAAyE,CAC1E;EACDC,GAAG,EAAE,CAAC,0BAA0B,CAAC;EACjCC,IAAI,EAAE,CACJ,mEAAmE,CACpE;EACDC,GAAG,EAAE,CAAC,+BAA+B,CAAC;EACtCC,IAAI,EAAE,CACJ,2EAA2E;AAE/E,CAAC,CAAC;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,0BAA+C,GAAG,IAAIpB,GAAG,CAAC,CAC9D,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CACnD,CAAC;;AAEF;;AA0BA,MAAMqB,0BAA0B,GAC9B,yEAAyE;;AAE3E;AACA,MAAMC,WAAW,GAAIC,QAA4B,IAAa;EAC5D,IAAI,CAACA,QAAQ,EAAE,OAAO,EAAE;EACxB,MAAMC,KAAK,GAAGD,QAAQ,CAACE,KAAK,CAAC,GAAG,CAAC;EACjC;AACF;EACE,IAAID,KAAK,CAACE,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE;EAC/B,OAAO,CAACF,KAAK,CAACA,KAAK,CAACE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,EAAEC,WAAW,CAAC,CAAC;AACtD,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,qBAAqBA,CACnCC,UAA6B,EACrB;EACR,OAAO,GAAGA,UAAU,CAACC,GAAG,CAAEC,GAAG,IAAKA,GAAG,CAACC,WAAW,CAAC,CAAC,CAAC,CAACC,IAAI,CAAC,IAAI,CAAC,GAAG;AACpE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,iBAAiBA,CAACL,UAA6B,EAAU;EACvE,OAAOA,UAAU,CAACC,GAAG,CAAEC,GAAG,IAAK,IAAIA,GAAG,CAACJ,WAAW,CAAC,CAAC,EAAE,CAAC,CAACM,IAAI,CAAC,GAAG,CAAC;AACnE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,qBAAqBA,CAACC,IAA8B,EAAW;EAC7E,MAAML,GAAG,GAAGT,WAAW,CAACc,IAAI,EAAEC,IAAI,CAAC;EACnC,OAAON,GAAG,KAAK,EAAE,IAAIhC,qBAAqB,CAACuC,GAAG,CAACP,GAAG,CAAC;AACrD;;AAEA;AACO,SAASQ,cAAcA,CAC5BH,IAA6B,EAC7BI,MAAwB,EACf;EACT,OAAOC,gBAAgB,CAACL,IAAI,EAAEI,MAAM,CAAC,KAAK,IAAI;AAChD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,gBAAgBA,CAC9BL,IAA6B,EAC7BI,MAAwB,EACF;EACtB,MAAME,iBAAiB,GACrBF,MAAM,CAACG,MAAM,EAAEC,UAAU,IAAIvB,0BAA0B;EACzD,MAAMwB,WAAW,GACfL,MAAM,CAACG,MAAM,EAAEG,IAAI,IACnB,qBAAqBlB,qBAAqB,CAACY,MAAM,CAACX,UAAU,CAAC,EAAE;EAEjE,IAAIM,qBAAqB,CAACC,IAAI,CAAC,EAAE;IAC/B,OAAO;MAAEW,MAAM,EAAE,YAAY;MAAEC,OAAO,EAAEN;IAAkB,CAAC;EAC7D;EAEA,MAAMX,GAAG,GAAGT,WAAW,CAACc,IAAI,EAAEC,IAAI,CAAC;EACnC,IAAIN,GAAG,KAAK,EAAE,EAAE,OAAO;IAAEgB,MAAM,EAAE,WAAW;IAAEC,OAAO,EAAEH;EAAY,CAAC;EAEpE,MAAMI,QAAQ,GAAGT,MAAM,CAACX,UAAU,CAACqB,IAAI,CACpCC,OAAO,IAAKA,OAAO,CAACxB,WAAW,CAAC,CAAC,KAAKI,GACzC,CAAC;EACD,IAAI,CAACkB,QAAQ,EAAE,OAAO;IAAEF,MAAM,EAAE,WAAW;IAAEC,OAAO,EAAEH;EAAY,CAAC;EAEnE,MAAMO,IAAI,GAAG,CAAChB,IAAI,EAAEU,IAAI,IAAI,EAAE,EAAEO,IAAI,CAAC,CAAC,CAAC1B,WAAW,CAAC,CAAC;EACpD,IAAIyB,IAAI,KAAK,EAAE,EAAE,OAAO,IAAI;EAC5B,IAAIA,IAAI,KAAK,0BAA0B,IAAIhC,0BAA0B,CAACkB,GAAG,CAACP,GAAG,CAAC,EAAE;IAC9E,OAAO,IAAI;EACb;EAEA,MAAMuB,QAAQ,GAAGrD,iBAAiB,CAAC8B,GAAG,CAAC;EACvC,IAAIuB,QAAQ,KAAKC,SAAS,EAAE,OAAO,IAAI;EACvC,IAAID,QAAQ,CAACE,QAAQ,CAACJ,IAAI,CAAC,EAAE,OAAO,IAAI;EAExC,OAAO;IAAEL,MAAM,EAAE,MAAM;IAAEC,OAAO,EAAEH;EAAY,CAAC;AACjD;AAEA,MAAMY,iBAAiB,GAAG;EACxBtB,qBAAqB;EACrBI,cAAc;EACdE,gBAAgB;EAChBb,qBAAqB;EACrBM;AACF,CAAC;AAAC,IAAAwB,QAAA,GAAAC,OAAA,CAAAC,OAAA,GACaH,iBAAiB","ignoreList":[]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fmtDate / fmtDateTime — render a date for DISPLAY.
|
|
3
|
+
*
|
|
4
|
+
* fmtDate("2026-03-05T14:30:00Z") → "05/03/2026"
|
|
5
|
+
* fmtDateTime("2026-03-05T14:30:00Z") → "05/03/2026 15:30" (local time)
|
|
6
|
+
* fmtDate(undefined) → "—"
|
|
7
|
+
* fmtDate("pas une date") → "—"
|
|
8
|
+
* fmtDate(d, { absent: "" }) → "" when there is no date
|
|
9
|
+
*
|
|
10
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
* WHY THIS BELONGS IN THE LIBRARY (capability gap G-51)
|
|
12
|
+
*
|
|
13
|
+
* The library already owns the money side of the same job — `fmtMoney`, same
|
|
14
|
+
* folder, same "—" for an absent value, for the same reason: a table cell must
|
|
15
|
+
* never read "NaN". It owned nothing for dates, which every GU screen renders
|
|
16
|
+
* far more often than amounts. So every module wrote its own, and the copies
|
|
17
|
+
* shared one defect:
|
|
18
|
+
*
|
|
19
|
+
* const fullformatDate = (stringDate) => {
|
|
20
|
+
* const date = new Date(stringDate);
|
|
21
|
+
* const day = formatIntoTwoDigits(date.getDate());
|
|
22
|
+
* …
|
|
23
|
+
*
|
|
24
|
+
* `new Date(undefined)` is an INVALID DATE whose every accessor returns `NaN`,
|
|
25
|
+
* so the helper rendered, literally:
|
|
26
|
+
*
|
|
27
|
+
* NaN/NaN/NaN NaN:NaN
|
|
28
|
+
*
|
|
29
|
+
* on any optional field — an update date, a visit date, a closure date — which
|
|
30
|
+
* is most of them. In `autorisation-admis-pour-conforme-fe` the guard had been
|
|
31
|
+
* added at CALL SITES one lot after another (lots 4 to 7) before being pulled
|
|
32
|
+
* into the module's own helper: treating the symptom eight times, because the
|
|
33
|
+
* one place where it cannot be forgotten is the formatter itself. That is the
|
|
34
|
+
* argument for owning it here rather than in each module.
|
|
35
|
+
*
|
|
36
|
+
* Two smaller things the same copies carried, fixed here by construction: a
|
|
37
|
+
* two-digit helper that returned `"08"` (string) or `12` (number) depending on
|
|
38
|
+
* the value, and an absent date rendered as an EMPTY string — indistinguishable
|
|
39
|
+
* from a cell that failed to render, where "—" says "we looked, there is
|
|
40
|
+
* nothing".
|
|
41
|
+
*
|
|
42
|
+
* WHY NO `moment`, THOUGH THE PACKAGE ALREADY DEPENDS ON IT
|
|
43
|
+
*
|
|
44
|
+
* `moment` is here for the pickers, and specifically for STRICT parsing against
|
|
45
|
+
* an explicit format (`patterns/_pickerSerialisation`) — reading
|
|
46
|
+
* `"31-12-2026"` back without guessing. That is the right use of it.
|
|
47
|
+
*
|
|
48
|
+
* Rendering an already-parsed instant as two numbers and a year is not. This
|
|
49
|
+
* folder is dependency-free on purpose (see `fileDownload`), and
|
|
50
|
+
* `moment(someString)` with no format falls back to `new Date` WHILE EMITTING A
|
|
51
|
+
* CONSOLE DEPRECATION WARNING — noise a display helper called once per table
|
|
52
|
+
* cell must not produce. Native padding has neither cost.
|
|
53
|
+
*
|
|
54
|
+
* TIME ZONE, STATED RATHER THAN IMPLIED. The output is in the VIEWER'S local
|
|
55
|
+
* zone (`getDate`, `getHours`…), which is what the module helpers this replaces
|
|
56
|
+
* did, and what a user expects of "date de dépôt". An instant sent as
|
|
57
|
+
* `…T23:30:00Z` therefore reads as the next day in Casablanca. If a screen ever
|
|
58
|
+
* needs the server's calendar day regardless of the reader, that is a DIFFERENT
|
|
59
|
+
* function and must be argued for on its own — silently switching this one to
|
|
60
|
+
* UTC would move dates by a day across the whole platform.
|
|
61
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
62
|
+
*/
|
|
63
|
+
/** What a formatter accepts: an API string, an epoch, or a `Date`. */
|
|
64
|
+
export type FmtDateInput = string | number | Date | null | undefined;
|
|
65
|
+
export type FmtDateOptions = {
|
|
66
|
+
/**
|
|
67
|
+
* Rendered when there is no usable date. Defaults to the em dash used as the
|
|
68
|
+
* platform's absence mark in tables and detail sheets.
|
|
69
|
+
*
|
|
70
|
+
* Pass `""` where an empty cell is the deliberate choice — a DataGrid column
|
|
71
|
+
* that must stay visually quiet, or a value on its way into a search payload,
|
|
72
|
+
* since an em dash travelling to a back-end as a criterion is worse than
|
|
73
|
+
* nothing. Both cases exist in the module this was raised from.
|
|
74
|
+
*
|
|
75
|
+
* NO `separator` OPTION, and that is a correction rather than an omission.
|
|
76
|
+
* The first draft had one, justified by a module helper documented as feeding
|
|
77
|
+
* search criteria "d'où le séparateur paramétrable". A grep of the module
|
|
78
|
+
* showed that helper has ZERO importers: the justification was dead code, so
|
|
79
|
+
* the knob was speculative surface on a certified API (§2.8 — minimum API
|
|
80
|
+
* surface). The emitted format is the charter's `DD/MM/YYYY`; a host needing
|
|
81
|
+
* another separator should say why here.
|
|
82
|
+
*/
|
|
83
|
+
absent?: string | undefined;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Day, month and year — `DD/MM/YYYY`.
|
|
87
|
+
*
|
|
88
|
+
* @param value - API string, epoch, or `Date`. Absent or unparseable → `absent`.
|
|
89
|
+
*/
|
|
90
|
+
export declare function fmtDate(value: FmtDateInput, opts?: FmtDateOptions): string;
|
|
91
|
+
/**
|
|
92
|
+
* Day, month, year, then hours and minutes — `DD/MM/YYYY HH:mm`.
|
|
93
|
+
*
|
|
94
|
+
* Seconds are deliberately absent: no GU screen displays them, and a second
|
|
95
|
+
* shown is a second a reader tries to interpret.
|
|
96
|
+
*/
|
|
97
|
+
export declare function fmtDateTime(value: FmtDateInput, opts?: FmtDateOptions): string;
|
|
98
|
+
declare const fmtDateApi: {
|
|
99
|
+
fmtDate: typeof fmtDate;
|
|
100
|
+
fmtDateTime: typeof fmtDateTime;
|
|
101
|
+
};
|
|
102
|
+
export default fmtDateApi;
|
|
103
|
+
//# sourceMappingURL=fmtDate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fmtDate.d.ts","sourceRoot":"","sources":["../../../src/lib/v2/utils/fmtDate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,sEAAsE;AACtE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAErE,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAqBF;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM,CAO9E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,cAAmB,GACxB,MAAM,CAOR;AAED,QAAA,MAAM,UAAU;;;CAA2B,CAAC;AAC5C,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
exports.fmtDate = fmtDate;
|
|
8
|
+
exports.fmtDateTime = fmtDateTime;
|
|
9
|
+
/**
|
|
10
|
+
* fmtDate / fmtDateTime — render a date for DISPLAY.
|
|
11
|
+
*
|
|
12
|
+
* fmtDate("2026-03-05T14:30:00Z") → "05/03/2026"
|
|
13
|
+
* fmtDateTime("2026-03-05T14:30:00Z") → "05/03/2026 15:30" (local time)
|
|
14
|
+
* fmtDate(undefined) → "—"
|
|
15
|
+
* fmtDate("pas une date") → "—"
|
|
16
|
+
* fmtDate(d, { absent: "" }) → "" when there is no date
|
|
17
|
+
*
|
|
18
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
* WHY THIS BELONGS IN THE LIBRARY (capability gap G-51)
|
|
20
|
+
*
|
|
21
|
+
* The library already owns the money side of the same job — `fmtMoney`, same
|
|
22
|
+
* folder, same "—" for an absent value, for the same reason: a table cell must
|
|
23
|
+
* never read "NaN". It owned nothing for dates, which every GU screen renders
|
|
24
|
+
* far more often than amounts. So every module wrote its own, and the copies
|
|
25
|
+
* shared one defect:
|
|
26
|
+
*
|
|
27
|
+
* const fullformatDate = (stringDate) => {
|
|
28
|
+
* const date = new Date(stringDate);
|
|
29
|
+
* const day = formatIntoTwoDigits(date.getDate());
|
|
30
|
+
* …
|
|
31
|
+
*
|
|
32
|
+
* `new Date(undefined)` is an INVALID DATE whose every accessor returns `NaN`,
|
|
33
|
+
* so the helper rendered, literally:
|
|
34
|
+
*
|
|
35
|
+
* NaN/NaN/NaN NaN:NaN
|
|
36
|
+
*
|
|
37
|
+
* on any optional field — an update date, a visit date, a closure date — which
|
|
38
|
+
* is most of them. In `autorisation-admis-pour-conforme-fe` the guard had been
|
|
39
|
+
* added at CALL SITES one lot after another (lots 4 to 7) before being pulled
|
|
40
|
+
* into the module's own helper: treating the symptom eight times, because the
|
|
41
|
+
* one place where it cannot be forgotten is the formatter itself. That is the
|
|
42
|
+
* argument for owning it here rather than in each module.
|
|
43
|
+
*
|
|
44
|
+
* Two smaller things the same copies carried, fixed here by construction: a
|
|
45
|
+
* two-digit helper that returned `"08"` (string) or `12` (number) depending on
|
|
46
|
+
* the value, and an absent date rendered as an EMPTY string — indistinguishable
|
|
47
|
+
* from a cell that failed to render, where "—" says "we looked, there is
|
|
48
|
+
* nothing".
|
|
49
|
+
*
|
|
50
|
+
* WHY NO `moment`, THOUGH THE PACKAGE ALREADY DEPENDS ON IT
|
|
51
|
+
*
|
|
52
|
+
* `moment` is here for the pickers, and specifically for STRICT parsing against
|
|
53
|
+
* an explicit format (`patterns/_pickerSerialisation`) — reading
|
|
54
|
+
* `"31-12-2026"` back without guessing. That is the right use of it.
|
|
55
|
+
*
|
|
56
|
+
* Rendering an already-parsed instant as two numbers and a year is not. This
|
|
57
|
+
* folder is dependency-free on purpose (see `fileDownload`), and
|
|
58
|
+
* `moment(someString)` with no format falls back to `new Date` WHILE EMITTING A
|
|
59
|
+
* CONSOLE DEPRECATION WARNING — noise a display helper called once per table
|
|
60
|
+
* cell must not produce. Native padding has neither cost.
|
|
61
|
+
*
|
|
62
|
+
* TIME ZONE, STATED RATHER THAN IMPLIED. The output is in the VIEWER'S local
|
|
63
|
+
* zone (`getDate`, `getHours`…), which is what the module helpers this replaces
|
|
64
|
+
* did, and what a user expects of "date de dépôt". An instant sent as
|
|
65
|
+
* `…T23:30:00Z` therefore reads as the next day in Casablanca. If a screen ever
|
|
66
|
+
* needs the server's calendar day regardless of the reader, that is a DIFFERENT
|
|
67
|
+
* function and must be argued for on its own — silently switching this one to
|
|
68
|
+
* UTC would move dates by a day across the whole platform.
|
|
69
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/** What a formatter accepts: an API string, an epoch, or a `Date`. */
|
|
73
|
+
|
|
74
|
+
/** The platform's absence mark — same value `fmtMoney` returns. */
|
|
75
|
+
const ABSENT = "—";
|
|
76
|
+
const pad2 = value => String(value).padStart(2, "0");
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Parse an input into a USABLE `Date`, or `null`.
|
|
80
|
+
*
|
|
81
|
+
* `null` for every unusable case — absent, empty string, unparseable, or an
|
|
82
|
+
* Invalid Date — so no caller can accidentally format `NaN`. The empty-string
|
|
83
|
+
* check is explicit because `new Date("")` is Invalid while `new Date(0)` is a
|
|
84
|
+
* legitimate instant (1970), and a falsy test would conflate them.
|
|
85
|
+
*/
|
|
86
|
+
const toUsableDate = value => {
|
|
87
|
+
if (value === null || value === undefined || value === "") return null;
|
|
88
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
89
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Day, month and year — `DD/MM/YYYY`.
|
|
94
|
+
*
|
|
95
|
+
* @param value - API string, epoch, or `Date`. Absent or unparseable → `absent`.
|
|
96
|
+
*/
|
|
97
|
+
function fmtDate(value, opts = {}) {
|
|
98
|
+
const date = toUsableDate(value);
|
|
99
|
+
if (date === null) return opts.absent ?? ABSENT;
|
|
100
|
+
return `${pad2(date.getDate())}/${pad2(date.getMonth() + 1)}/${date.getFullYear()}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Day, month, year, then hours and minutes — `DD/MM/YYYY HH:mm`.
|
|
105
|
+
*
|
|
106
|
+
* Seconds are deliberately absent: no GU screen displays them, and a second
|
|
107
|
+
* shown is a second a reader tries to interpret.
|
|
108
|
+
*/
|
|
109
|
+
function fmtDateTime(value, opts = {}) {
|
|
110
|
+
const date = toUsableDate(value);
|
|
111
|
+
if (date === null) return opts.absent ?? ABSENT;
|
|
112
|
+
return `${fmtDate(date, opts)} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
|
|
113
|
+
}
|
|
114
|
+
const fmtDateApi = {
|
|
115
|
+
fmtDate,
|
|
116
|
+
fmtDateTime
|
|
117
|
+
};
|
|
118
|
+
var _default = exports.default = fmtDateApi;
|
|
119
|
+
//# sourceMappingURL=fmtDate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fmtDate.js","names":["ABSENT","pad2","value","String","padStart","toUsableDate","undefined","date","Date","Number","isNaN","getTime","fmtDate","opts","absent","getDate","getMonth","getFullYear","fmtDateTime","getHours","getMinutes","fmtDateApi","_default","exports","default"],"sources":["../../../src/lib/v2/utils/fmtDate.ts"],"sourcesContent":["/**\r\n * fmtDate / fmtDateTime — render a date for DISPLAY.\r\n *\r\n * fmtDate(\"2026-03-05T14:30:00Z\") → \"05/03/2026\"\r\n * fmtDateTime(\"2026-03-05T14:30:00Z\") → \"05/03/2026 15:30\" (local time)\r\n * fmtDate(undefined) → \"—\"\r\n * fmtDate(\"pas une date\") → \"—\"\r\n * fmtDate(d, { absent: \"\" }) → \"\" when there is no date\r\n *\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n * WHY THIS BELONGS IN THE LIBRARY (capability gap G-51)\r\n *\r\n * The library already owns the money side of the same job — `fmtMoney`, same\r\n * folder, same \"—\" for an absent value, for the same reason: a table cell must\r\n * never read \"NaN\". It owned nothing for dates, which every GU screen renders\r\n * far more often than amounts. So every module wrote its own, and the copies\r\n * shared one defect:\r\n *\r\n * const fullformatDate = (stringDate) => {\r\n * const date = new Date(stringDate);\r\n * const day = formatIntoTwoDigits(date.getDate());\r\n * …\r\n *\r\n * `new Date(undefined)` is an INVALID DATE whose every accessor returns `NaN`,\r\n * so the helper rendered, literally:\r\n *\r\n * NaN/NaN/NaN NaN:NaN\r\n *\r\n * on any optional field — an update date, a visit date, a closure date — which\r\n * is most of them. In `autorisation-admis-pour-conforme-fe` the guard had been\r\n * added at CALL SITES one lot after another (lots 4 to 7) before being pulled\r\n * into the module's own helper: treating the symptom eight times, because the\r\n * one place where it cannot be forgotten is the formatter itself. That is the\r\n * argument for owning it here rather than in each module.\r\n *\r\n * Two smaller things the same copies carried, fixed here by construction: a\r\n * two-digit helper that returned `\"08\"` (string) or `12` (number) depending on\r\n * the value, and an absent date rendered as an EMPTY string — indistinguishable\r\n * from a cell that failed to render, where \"—\" says \"we looked, there is\r\n * nothing\".\r\n *\r\n * WHY NO `moment`, THOUGH THE PACKAGE ALREADY DEPENDS ON IT\r\n *\r\n * `moment` is here for the pickers, and specifically for STRICT parsing against\r\n * an explicit format (`patterns/_pickerSerialisation`) — reading\r\n * `\"31-12-2026\"` back without guessing. That is the right use of it.\r\n *\r\n * Rendering an already-parsed instant as two numbers and a year is not. This\r\n * folder is dependency-free on purpose (see `fileDownload`), and\r\n * `moment(someString)` with no format falls back to `new Date` WHILE EMITTING A\r\n * CONSOLE DEPRECATION WARNING — noise a display helper called once per table\r\n * cell must not produce. Native padding has neither cost.\r\n *\r\n * TIME ZONE, STATED RATHER THAN IMPLIED. The output is in the VIEWER'S local\r\n * zone (`getDate`, `getHours`…), which is what the module helpers this replaces\r\n * did, and what a user expects of \"date de dépôt\". An instant sent as\r\n * `…T23:30:00Z` therefore reads as the next day in Casablanca. If a screen ever\r\n * needs the server's calendar day regardless of the reader, that is a DIFFERENT\r\n * function and must be argued for on its own — silently switching this one to\r\n * UTC would move dates by a day across the whole platform.\r\n * ─────────────────────────────────────────────────────────────────────────────\r\n */\r\n\r\n/** What a formatter accepts: an API string, an epoch, or a `Date`. */\r\nexport type FmtDateInput = string | number | Date | null | undefined;\r\n\r\nexport type FmtDateOptions = {\r\n /**\r\n * Rendered when there is no usable date. Defaults to the em dash used as the\r\n * platform's absence mark in tables and detail sheets.\r\n *\r\n * Pass `\"\"` where an empty cell is the deliberate choice — a DataGrid column\r\n * that must stay visually quiet, or a value on its way into a search payload,\r\n * since an em dash travelling to a back-end as a criterion is worse than\r\n * nothing. Both cases exist in the module this was raised from.\r\n *\r\n * NO `separator` OPTION, and that is a correction rather than an omission.\r\n * The first draft had one, justified by a module helper documented as feeding\r\n * search criteria \"d'où le séparateur paramétrable\". A grep of the module\r\n * showed that helper has ZERO importers: the justification was dead code, so\r\n * the knob was speculative surface on a certified API (§2.8 — minimum API\r\n * surface). The emitted format is the charter's `DD/MM/YYYY`; a host needing\r\n * another separator should say why here.\r\n */\r\n absent?: string | undefined;\r\n};\r\n\r\n/** The platform's absence mark — same value `fmtMoney` returns. */\r\nconst ABSENT = \"—\";\r\n\r\nconst pad2 = (value: number): string => String(value).padStart(2, \"0\");\r\n\r\n/**\r\n * Parse an input into a USABLE `Date`, or `null`.\r\n *\r\n * `null` for every unusable case — absent, empty string, unparseable, or an\r\n * Invalid Date — so no caller can accidentally format `NaN`. The empty-string\r\n * check is explicit because `new Date(\"\")` is Invalid while `new Date(0)` is a\r\n * legitimate instant (1970), and a falsy test would conflate them.\r\n */\r\nconst toUsableDate = (value: FmtDateInput): Date | null => {\r\n if (value === null || value === undefined || value === \"\") return null;\r\n const date = value instanceof Date ? value : new Date(value);\r\n return Number.isNaN(date.getTime()) ? null : date;\r\n};\r\n\r\n/**\r\n * Day, month and year — `DD/MM/YYYY`.\r\n *\r\n * @param value - API string, epoch, or `Date`. Absent or unparseable → `absent`.\r\n */\r\nexport function fmtDate(value: FmtDateInput, opts: FmtDateOptions = {}): string {\r\n const date = toUsableDate(value);\r\n if (date === null) return opts.absent ?? ABSENT;\r\n\r\n return `${pad2(date.getDate())}/${pad2(\r\n date.getMonth() + 1\r\n )}/${date.getFullYear()}`;\r\n}\r\n\r\n/**\r\n * Day, month, year, then hours and minutes — `DD/MM/YYYY HH:mm`.\r\n *\r\n * Seconds are deliberately absent: no GU screen displays them, and a second\r\n * shown is a second a reader tries to interpret.\r\n */\r\nexport function fmtDateTime(\r\n value: FmtDateInput,\r\n opts: FmtDateOptions = {}\r\n): string {\r\n const date = toUsableDate(value);\r\n if (date === null) return opts.absent ?? ABSENT;\r\n\r\n return `${fmtDate(date, opts)} ${pad2(date.getHours())}:${pad2(\r\n date.getMinutes()\r\n )}`;\r\n}\r\n\r\nconst fmtDateApi = { fmtDate, fmtDateTime };\r\nexport default fmtDateApi;\r\n"],"mappings":";;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAwBA;AACA,MAAMA,MAAM,GAAG,GAAG;AAElB,MAAMC,IAAI,GAAIC,KAAa,IAAaC,MAAM,CAACD,KAAK,CAAC,CAACE,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;;AAEtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,YAAY,GAAIH,KAAmB,IAAkB;EACzD,IAAIA,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKI,SAAS,IAAIJ,KAAK,KAAK,EAAE,EAAE,OAAO,IAAI;EACtE,MAAMK,IAAI,GAAGL,KAAK,YAAYM,IAAI,GAAGN,KAAK,GAAG,IAAIM,IAAI,CAACN,KAAK,CAAC;EAC5D,OAAOO,MAAM,CAACC,KAAK,CAACH,IAAI,CAACI,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,GAAGJ,IAAI;AACnD,CAAC;;AAED;AACA;AACA;AACA;AACA;AACO,SAASK,OAAOA,CAACV,KAAmB,EAAEW,IAAoB,GAAG,CAAC,CAAC,EAAU;EAC9E,MAAMN,IAAI,GAAGF,YAAY,CAACH,KAAK,CAAC;EAChC,IAAIK,IAAI,KAAK,IAAI,EAAE,OAAOM,IAAI,CAACC,MAAM,IAAId,MAAM;EAE/C,OAAO,GAAGC,IAAI,CAACM,IAAI,CAACQ,OAAO,CAAC,CAAC,CAAC,IAAId,IAAI,CACpCM,IAAI,CAACS,QAAQ,CAAC,CAAC,GAAG,CACpB,CAAC,IAAIT,IAAI,CAACU,WAAW,CAAC,CAAC,EAAE;AAC3B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,WAAWA,CACzBhB,KAAmB,EACnBW,IAAoB,GAAG,CAAC,CAAC,EACjB;EACR,MAAMN,IAAI,GAAGF,YAAY,CAACH,KAAK,CAAC;EAChC,IAAIK,IAAI,KAAK,IAAI,EAAE,OAAOM,IAAI,CAACC,MAAM,IAAId,MAAM;EAE/C,OAAO,GAAGY,OAAO,CAACL,IAAI,EAAEM,IAAI,CAAC,IAAIZ,IAAI,CAACM,IAAI,CAACY,QAAQ,CAAC,CAAC,CAAC,IAAIlB,IAAI,CAC5DM,IAAI,CAACa,UAAU,CAAC,CAClB,CAAC,EAAE;AACL;AAEA,MAAMC,UAAU,GAAG;EAAET,OAAO;EAAEM;AAAY,CAAC;AAAC,IAAAI,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAC7BH,UAAU","ignoreList":[]}
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* fmtMoney(null) / fmtMoney("abc") / fmtMoney(Infinity) → "—"
|
|
20
20
|
*/
|
|
21
21
|
type FmtMoneyOptions = {
|
|
22
|
-
locale?: string;
|
|
23
|
-
minimumFractionDigits?: number;
|
|
24
|
-
maximumFractionDigits?: number;
|
|
22
|
+
locale?: string | undefined;
|
|
23
|
+
minimumFractionDigits?: number | undefined;
|
|
24
|
+
maximumFractionDigits?: number | undefined;
|
|
25
25
|
};
|
|
26
26
|
export default function fmtMoney(n: number | string | null | undefined, currency?: string, opts?: FmtMoneyOptions): string;
|
|
27
27
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fmtMoney.d.ts","sourceRoot":"","sources":["../../../src/lib/v2/utils/fmtMoney.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,KAAK,eAAe,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"fmtMoney.d.ts","sourceRoot":"","sources":["../../../src/lib/v2/utils/fmtMoney.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,KAAK,eAAe,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C,CAAC;AA+BF,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EACrC,QAAQ,GAAE,MAAW,EACrB,IAAI,GAAE,eAAoB,GACzB,MAAM,CAgCR"}
|