@jmruthers/pace-core 0.6.9 → 0.6.10
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/audit-tool/audits/02-project-structure.cjs +62 -0
- package/audit-tool/audits/03-architecture.cjs +145 -19
- package/audit-tool/audits/04-code-quality.cjs +86 -1
- package/audit-tool/audits/06-security-rbac.cjs +109 -11
- package/cursor-rules/02-project-structure.mdc +2 -26
- package/cursor-rules/05-styling.mdc +84 -6
- package/cursor-rules/06-security-rbac.mdc +124 -1
- package/dist/{DataTable-SOAFXIWY.js → DataTable-SAXFG4XI.js} +11 -13
- package/dist/{AuthService-DmfO5rGS.d.ts → InactivityServiceProvider-DHryoh6K.d.ts} +24 -249
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +7 -0
- package/dist/{UnifiedAuthProvider-CKvHP1MK.d.ts → UnifiedAuthProvider-CiBAl9-s.d.ts} +34 -22
- package/dist/{api-7P7DI652.js → api-F47QJ7FX.js} +3 -3
- package/dist/assets/app-icons/admin_favicon.svg +462 -0
- package/dist/assets/app-icons/base_favicon.svg +85 -0
- package/dist/assets/app-icons/cake_favicon.svg +68 -0
- package/dist/assets/app-icons/core_favicon.svg +256 -0
- package/dist/assets/app-icons/gear_favicon.svg +91 -0
- package/dist/assets/app-icons/medi_favicon.svg +92 -0
- package/dist/assets/app-icons/mint_favicon.svg +83 -0
- package/dist/assets/app-icons/pace_favicon.svg +49 -0
- package/dist/assets/app-icons/pump_favicon.svg +68 -0
- package/dist/assets/app-icons/seed_favicon.svg +91 -0
- package/dist/assets/app-icons/team_favicon.svg +67 -0
- package/dist/assets/app-icons/trac_favicon.svg +112 -0
- package/dist/assets/app-icons/trip_favicon.svg +102 -0
- package/dist/audit-Z6ZZBWLU.js +3 -0
- package/dist/chunk-3GWSPISD.js +61 -0
- package/dist/{chunk-4DDCYDQ3.js → chunk-66R6RLUZ.js} +12 -27
- package/dist/{chunk-FYHN4DD5.js → chunk-7YDC7LMU.js} +80 -8
- package/dist/{chunk-S7DKJPLT.js → chunk-BCTXBU6U.js} +22 -17
- package/dist/{chunk-TTRFSOKR.js → chunk-BTHN5MKC.js} +4 -4
- package/dist/{chunk-A3W6LW53.js → chunk-DDMPHZ3D.js} +6 -18
- package/dist/{chunk-MPBLMWVR.js → chunk-FBZ7U3ID.js} +140 -92
- package/dist/chunk-FN52B75D.js +246 -0
- package/dist/{chunk-5W2A3DRC.js → chunk-JJEYZ3DX.js} +5 -4
- package/dist/chunk-KPYQWGFQ.js +183 -0
- package/dist/{chunk-C7ZQ5O4C.js → chunk-KSNLMI7N.js} +3 -3
- package/dist/chunk-KYURMOQM.js +977 -0
- package/dist/{chunk-LX6U42O3.js → chunk-LNHFAF4X.js} +160 -58
- package/dist/{chunk-J2U36LHD.js → chunk-MPY44PWB.js} +620 -627
- package/dist/{chunk-AHU7G2R5.js → chunk-NIU6DPQV.js} +10 -6
- package/dist/{chunk-HF6O3O37.js → chunk-RMLY6KB5.js} +1 -1
- package/dist/{chunk-6GLLNA6U.js → chunk-SACF5YSM.js} +1 -1
- package/dist/{chunk-5HNSDQWH.js → chunk-TFIPNIPE.js} +865 -532
- package/dist/{chunk-OJ4SKRSV.js → chunk-UZNAFKGW.js} +25 -5
- package/dist/chunk-W46INAVW.js +1216 -0
- package/dist/chunk-X5EAU5G7.js +793 -0
- package/dist/{chunk-T5CVK4R3.js → chunk-Y4PF6HIM.js} +110 -64
- package/dist/components.d.ts +8 -86
- package/dist/components.js +21 -55
- package/dist/eslint-rules/rules/05-styling.cjs +507 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +10 -0
- package/dist/{event-CW5YB_2p.d.ts → event-WTAQuGcq.d.ts} +1 -1
- package/dist/{functions-lBy5L2ry.d.ts → functions-DH45k8ec.d.ts} +1 -1
- package/dist/hooks.d.ts +11 -10
- package/dist/hooks.js +69 -44
- package/dist/index.d.ts +379 -31
- package/dist/index.js +46 -32
- package/dist/papaparseLoader-WG2UXQ22.js +7 -0
- package/dist/providers.d.ts +28 -14
- package/dist/providers.js +5 -5
- package/dist/rbac/eslint-rules.js +2 -2
- package/dist/rbac/index.d.ts +57 -213
- package/dist/rbac/index.js +11 -11
- package/dist/theming/runtime.d.ts +9 -3
- package/dist/theming/runtime.js +2 -2
- package/dist/{timezone-0AyangqX.d.ts → timezone-K-ptz3HO.d.ts} +21 -22
- package/dist/{types-t9H8qKRw.d.ts → types-BE2sEHKd.d.ts} +1 -1
- package/dist/{types-BeoeWV5I.d.ts → types-CvOPXWWZ.d.ts} +6 -5
- package/dist/{types-DXstZpNI.d.ts → types-D05dCGma.d.ts} +56 -149
- package/dist/types-Dr8sNhER.d.ts +50 -0
- package/dist/types.d.ts +4 -4
- package/dist/{PublicPageProvider-CIGSujI2.d.ts → usePublicPageContext-vxBlEHO9.d.ts} +294 -151
- package/dist/{usePublicRouteParams-DQLrDqDb.d.ts → usePublicRouteParams-G3Ks53mk.d.ts} +7 -6
- package/dist/utils.d.ts +300 -136
- package/dist/utils.js +42 -41
- package/dist/{validation-643vUDZW.d.ts → validation-g5n0hDkh.d.ts} +2 -2
- package/docs/api/modules.md +542 -549
- package/docs/api-reference/components.md +5 -5
- package/docs/implementation-guides/data-tables.md +190 -8
- package/docs/rbac/RBAC_CONTRACT.md +0 -12
- package/docs/standards/2-project-structure-standards.md +12 -74
- package/docs/standards/6-security-rbac-standards.md +222 -7
- package/docs/standards/7-api-tech-stack-standards.md +91 -3
- package/docs/testing/README.md +10 -0
- package/docs/testing/test-setup-for-consumers.md +914 -0
- package/eslint-config-pace-core.cjs +4 -0
- package/package.json +1 -1
- package/scripts/eslint-audit.cjs +110 -11
- package/src/__mocks__/lucide-react.ts +0 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -2
- package/src/__tests__/index.test.ts +532 -0
- package/src/__tests__/integration/UserProfile.test.tsx +1 -1
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -8
- package/src/__tests__/rls-policies.test.ts +3 -2
- package/src/assets/app-icons/admin_favicon.svg +462 -0
- package/src/assets/app-icons/base_favicon.svg +85 -0
- package/src/assets/app-icons/cake_favicon.svg +68 -0
- package/src/assets/app-icons/core_favicon.svg +256 -0
- package/src/assets/app-icons/gear_favicon.svg +91 -0
- package/src/assets/app-icons/index.ts +83 -0
- package/src/assets/app-icons/medi_favicon.svg +92 -0
- package/src/assets/app-icons/mint_favicon.svg +83 -0
- package/src/assets/app-icons/pace_favicon.svg +49 -0
- package/src/assets/app-icons/pump_favicon.svg +68 -0
- package/src/assets/app-icons/seed_favicon.svg +91 -0
- package/src/assets/app-icons/team_favicon.svg +67 -0
- package/src/assets/app-icons/trac_favicon.svg +112 -0
- package/src/assets/app-icons/trip_favicon.svg +102 -0
- package/src/components/AddressField/AddressField.test.tsx +378 -3
- package/src/components/AddressField/AddressField.tsx +2 -2
- package/src/components/AddressField/types.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +35 -25
- package/src/components/Alert/Alert.tsx +8 -8
- package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
- package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
- package/src/components/Avatar/Avatar.test.tsx +11 -1
- package/src/components/Avatar/Avatar.tsx +3 -2
- package/src/components/Badge/Badge.test.tsx +11 -1
- package/src/components/Button/Button.test.tsx +13 -3
- package/src/components/Calendar/Calendar.test.tsx +523 -131
- package/src/components/Calendar/Calendar.tsx +107 -488
- package/src/components/Card/Card.test.tsx +220 -249
- package/src/components/Checkbox/Checkbox.test.tsx +58 -174
- package/src/components/ContextSelector/ContextSelector.tsx +3 -3
- package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +360 -0
- package/src/components/DataTable/DataTable.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +16 -14
- package/src/components/DataTable/__tests__/DataTable.test.tsx +2 -2
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +1 -1
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +76 -580
- package/src/components/DataTable/__tests__/README.md +1 -1
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +1 -1
- package/src/components/DataTable/__tests__/keyboard.test.tsx +1 -1
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +1 -3
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -6
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +14 -6
- package/src/components/DataTable/components/ActionButtons.tsx +9 -4
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/components/ColumnFilter.tsx +2 -7
- package/src/components/DataTable/components/DataTableCore.tsx +44 -52
- package/src/components/DataTable/components/DataTableLayout.tsx +37 -26
- package/src/components/DataTable/components/DataTableModals.tsx +118 -30
- package/src/components/DataTable/components/DataTableToolbar.tsx +2 -2
- package/src/components/DataTable/components/EditFields.tsx +6 -47
- package/src/components/DataTable/components/EditableRow.tsx +8 -8
- package/src/components/DataTable/components/EmptyState.tsx +6 -3
- package/src/components/DataTable/components/FilterRow.tsx +18 -11
- package/src/components/DataTable/components/GroupingDropdown.tsx +0 -1
- package/src/components/DataTable/components/ImportModal.tsx +305 -133
- package/src/components/DataTable/components/LoadingState.tsx +2 -2
- package/src/components/DataTable/components/PaginationControls.tsx +0 -4
- package/src/components/DataTable/components/RowComponent.tsx +42 -22
- package/src/components/DataTable/components/UnifiedTableBody.tsx +52 -12
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +51 -463
- package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +122 -116
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +40 -68
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +9 -137
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +57 -17
- package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +792 -0
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +24 -65
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +467 -0
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +8 -125
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +528 -56
- package/src/components/DataTable/components/__tests__/EditFields.test.tsx +526 -0
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +1 -68
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +8 -25
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +3 -62
- package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +9 -14
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +50 -186
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +39 -97
- package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +13 -103
- package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +629 -0
- package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +135 -0
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +31 -171
- package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +453 -0
- package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +184 -0
- package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +381 -0
- package/src/components/DataTable/context/DataTableContext.tsx +9 -10
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +12 -26
- package/src/components/DataTable/core/ColumnFactory.ts +3 -3
- package/src/components/DataTable/core/ColumnManager.ts +0 -1
- package/src/components/DataTable/core/DataManager.ts +4 -2
- package/src/components/DataTable/core/LocalDataAdapter.ts +1 -1
- package/src/components/DataTable/core/PluginRegistry.ts +2 -2
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +114 -2
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +103 -5
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +57 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +63 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +42 -9
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +29 -7
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +58 -4
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +16 -21
- package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +93 -4
- package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +227 -54
- package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +215 -62
- package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +217 -39
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +101 -6
- package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +157 -27
- package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +80 -0
- package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +787 -0
- package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +258 -0
- package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +128 -77
- package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +440 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +1 -1
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +11 -22
- package/src/components/DataTable/hooks/useDataTableState.ts +20 -24
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +5 -5
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +13 -1
- package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
- package/src/components/DataTable/hooks/useTableHandlers.ts +8 -20
- package/src/components/DataTable/index.ts +24 -2
- package/src/components/DataTable/types.ts +6 -3
- package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +3 -67
- package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +288 -0
- package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +3 -60
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +1 -1
- package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +9 -21
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +102 -86
- package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +593 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +33 -49
- package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +1 -0
- package/src/components/DataTable/utils/a11yUtils.ts +1 -1
- package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
- package/src/components/DataTable/utils/errorHandling.ts +3 -1
- package/src/components/DataTable/utils/exportUtils.ts +1 -1
- package/src/components/DataTable/utils/flexibleImport.ts +2 -2
- package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
- package/src/components/DataTable/utils/paginationUtils.ts +1 -1
- package/src/components/DataTable/utils/performanceUtils.ts +1 -1
- package/src/components/DataTable/utils/selectFieldUtils.ts +0 -7
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +17 -24
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +2 -15
- package/src/components/DateTimeField/DateTimeField.tsx +1 -1
- package/src/components/Dialog/Dialog.test.tsx +2007 -407
- package/src/components/Dialog/Dialog.tsx +97 -192
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
- package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
- package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
- package/src/components/ErrorBoundary/index.ts +3 -4
- package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +454 -222
- package/src/components/FileDisplay/FileDisplay.tsx +14 -12
- package/src/components/FileDisplay/index.tsx +1 -1
- package/src/components/FileUpload/FileUpload.test.tsx +54 -18
- package/src/components/FileUpload/FileUpload.tsx +10 -7
- package/src/components/FileUpload/index.tsx +1 -1
- package/src/components/Footer/Footer.test.tsx +33 -114
- package/src/components/Form/Form.test.tsx +388 -68
- package/src/components/Form/Form.tsx +57 -42
- package/src/components/Header/Header.test.tsx +645 -154
- package/src/components/Header/Header.tsx +52 -43
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
- package/src/components/Input/Input.test.tsx +34 -120
- package/src/components/Label/Label.test.tsx +47 -46
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +9 -12
- package/src/components/LoginForm/LoginForm.test.tsx +0 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1399 -82
- package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
- package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +1934 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +5 -15
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1307 -0
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +47 -46
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +87 -66
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +245 -39
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -20
- package/src/components/PaceAppLayout/README.md +0 -9
- package/src/components/PaceAppLayout/test-setup.tsx +15 -9
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +759 -3
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +2 -3
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
- package/src/components/Progress/Progress.test.tsx +127 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +24 -6
- package/src/components/PublicLayout/PublicLayout.test.tsx +1435 -14
- package/src/components/PublicLayout/PublicPageContext.ts +28 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +2 -41
- package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
- package/src/components/Select/Select.test.tsx +46 -9
- package/src/components/Select/Select.tsx +31 -24
- package/src/components/Select/__tests__/context.test.tsx +56 -0
- package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +279 -0
- package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +295 -0
- package/src/components/Select/hooks/__tests__/useSelectState.test.ts +254 -0
- package/src/components/Select/hooks/useSelectState.ts +16 -16
- package/src/components/Select/types.ts +3 -0
- package/src/components/Select/utils/__tests__/text.test.tsx +104 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
- package/src/components/Switch/Switch.test.tsx +57 -153
- package/src/components/Table/Table.test.tsx +47 -317
- package/src/components/Tabs/Tabs.tsx +3 -3
- package/src/components/Textarea/Textarea.test.tsx +11 -38
- package/src/components/Toast/Toast.test.tsx +78 -569
- package/src/components/Tooltip/Tooltip.test.tsx +4 -21
- package/src/components/UserMenu/UserMenu.test.tsx +1 -21
- package/src/components/UserMenu/UserMenu.tsx +0 -1
- package/src/components/__tests__/index.test.ts +346 -0
- package/src/components/index.ts +12 -1
- package/src/constants/__tests__/performance.test.ts +91 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +239 -129
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -3
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +1 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +88 -29
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +282 -98
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +53 -109
- package/src/hooks/__tests__/useDataTableState.test.ts +143 -49
- package/src/hooks/__tests__/useDebounce.unit.test.ts +94 -19
- package/src/hooks/__tests__/useEvents.unit.test.ts +100 -125
- package/src/hooks/__tests__/useFileDisplay.test.ts +540 -0
- package/src/hooks/__tests__/useFileDisplay.unit.test.ts +1 -4
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +27 -247
- package/src/hooks/__tests__/useFileUrlCache.test.ts +246 -56
- package/src/hooks/__tests__/useFocusManagement.unit.test.ts +442 -68
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +345 -560
- package/src/hooks/__tests__/useFormDialog.test.ts +51 -222
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +1 -1
- package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +1 -4
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -1
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +1 -1
- package/src/hooks/__tests__/usePermissionCache.test.ts +506 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +255 -36
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +17 -8
- package/src/hooks/__tests__/usePublicEvent.test.ts +16 -24
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +12 -4
- package/src/hooks/__tests__/usePublicFileDisplay.test.ts +3 -6
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +1 -2
- package/src/hooks/__tests__/useQueryCache.test.ts +313 -66
- package/src/hooks/__tests__/useSessionDraft.test.ts +496 -103
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +2 -2
- package/src/hooks/__tests__/useStorage.unit.test.ts +72 -102
- package/src/hooks/__tests__/useToast.test.ts +413 -0
- package/src/hooks/__tests__/useToast.unit.test.tsx +1 -1
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +175 -21
- package/src/hooks/index.ts +13 -1
- package/src/hooks/public/usePublicEvent.test.ts +304 -0
- package/src/hooks/public/usePublicEvent.ts +11 -11
- package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
- package/src/hooks/public/usePublicEventLogo.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.test.ts +723 -0
- package/src/hooks/public/usePublicFileDisplay.ts +79 -49
- package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
- package/src/hooks/public/usePublicRouteParams.ts +2 -2
- package/src/hooks/services/useAuthService.ts +1 -1
- package/src/hooks/services/useEventService.ts +1 -1
- package/src/hooks/useAccessibleApps.test.ts +400 -0
- package/src/hooks/useAccessibleApps.ts +264 -0
- package/src/hooks/useAddressAutocomplete.test.ts +165 -42
- package/src/hooks/useAddressAutocomplete.ts +41 -28
- package/src/hooks/useAppConfig.ts +13 -3
- package/src/hooks/useDataTablePerformance.ts +13 -12
- package/src/hooks/useDataTableState.ts +5 -5
- package/src/hooks/useEventTheme.test.ts +66 -17
- package/src/hooks/useEventTheme.ts +1 -1
- package/src/hooks/useEvents.ts +8 -1
- package/src/hooks/useFileDisplay.ts +66 -33
- package/src/hooks/useFileReference.test.ts +365 -87
- package/src/hooks/useFileReference.ts +2 -6
- package/src/hooks/useFileUrlCache.ts +4 -1
- package/src/hooks/useFormDialog.ts +2 -2
- package/src/hooks/useInactivityTracker.ts +3 -3
- package/src/hooks/useOrganisationPermissions.test.ts +1 -2
- package/src/hooks/useOrganisationPermissions.ts +1 -4
- package/src/hooks/useOrganisationSecurity.test.ts +1 -30
- package/src/hooks/useOrganisationSecurity.ts +3 -3
- package/src/hooks/useOrganisations.ts +1 -1
- package/src/hooks/usePerformanceMonitor.ts +1 -1
- package/src/hooks/usePermissionCache.ts +2 -6
- package/src/hooks/useQueryCache.ts +7 -7
- package/src/hooks/useSessionDraft.ts +14 -11
- package/src/hooks/useSessionRestoration.ts +1 -1
- package/src/hooks/useStorage.ts +75 -40
- package/src/hooks/useToast.ts +2 -2
- package/src/hooks/useZodForm.ts +3 -3
- package/src/icons/__tests__/index.test.ts +133 -0
- package/src/icons/index.ts +1 -1
- package/src/index.ts +43 -4
- package/src/providers/OrganisationProvider.test.tsx +40 -0
- package/src/providers/OrganisationProvider.tsx +5 -5
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
- package/src/providers/__tests__/AuthProvider.test.tsx +22 -91
- package/src/providers/__tests__/EventProvider.test.tsx +16 -80
- package/src/providers/__tests__/InactivityProvider.test.tsx +29 -173
- package/src/providers/__tests__/OrganisationProvider.test.tsx +4 -5
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +591 -0
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +80 -196
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +40 -133
- package/src/providers/__tests__/index.test.ts +138 -0
- package/src/providers/services/AuthServiceContext.ts +27 -0
- package/src/providers/services/AuthServiceProvider.tsx +81 -20
- package/src/providers/services/EventServiceContext.ts +25 -0
- package/src/providers/services/EventServiceProvider.tsx +11 -20
- package/src/providers/services/InactivityServiceContext.ts +25 -0
- package/src/providers/services/InactivityServiceProvider.tsx +7 -17
- package/src/providers/services/OrganisationServiceContext.ts +25 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
- package/src/providers/services/UnifiedAuthContext.ts +99 -0
- package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +38 -143
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +61 -95
- package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +638 -0
- package/src/providers/services/__tests__/EventServiceProvider.test.tsx +839 -0
- package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +662 -0
- package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +440 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +435 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +408 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +55 -48
- package/src/providers/services/__tests__/contexts.test.tsx +281 -0
- package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +251 -0
- package/src/providers/services/useUnifiedAuth.ts +29 -0
- package/src/rbac/README.md +5 -5
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +9 -14
- package/src/rbac/__tests__/audit-batched.test.ts +550 -0
- package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +1 -14
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +43 -12
- package/src/rbac/__tests__/cache-invalidation.test.ts +8 -14
- package/src/rbac/__tests__/engine.comprehensive.test.ts +2 -7
- package/src/rbac/__tests__/index.test.ts +107 -0
- package/src/rbac/__tests__/performance.test.ts +451 -0
- package/src/rbac/__tests__/rbac-core.test.tsx +2 -2
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -5
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +1 -7
- package/src/rbac/__tests__/rbac-functions.test.ts +0 -1
- package/src/rbac/__tests__/rbac-integration.test.ts +0 -1
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +21 -32
- package/src/rbac/adapters.test.tsx +654 -0
- package/src/rbac/adapters.tsx +24 -9
- package/src/rbac/api.test.ts +13 -217
- package/src/rbac/api.ts +85 -16
- package/src/rbac/audit-batched.ts +5 -4
- package/src/rbac/audit.test.ts +225 -28
- package/src/rbac/audit.ts +22 -17
- package/src/rbac/cache-invalidation.ts +18 -15
- package/src/rbac/cache.test.ts +123 -63
- package/src/rbac/cache.ts +3 -4
- package/src/rbac/components/AccessDenied.tsx +20 -18
- package/src/rbac/components/NavigationGuard.tsx +10 -8
- package/src/rbac/components/PagePermissionGuard.tsx +27 -25
- package/src/rbac/components/__tests__/AccessDenied.test.tsx +324 -0
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +242 -71
- package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +20 -37
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +18 -17
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +452 -129
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -13
- package/src/rbac/config.test.ts +131 -48
- package/src/rbac/config.ts +11 -8
- package/src/rbac/docs/event-based-apps.md +26 -13
- package/src/rbac/engine.test.ts +496 -146
- package/src/rbac/engine.ts +53 -13
- package/src/rbac/errors.test.ts +99 -87
- package/src/rbac/eslint-rules.js +2 -2
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -5
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +601 -1
- package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +622 -0
- package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +798 -0
- package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +843 -0
- package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +545 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +7 -8
- package/src/rbac/hooks/permissions/useCan.ts +12 -10
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +57 -8
- package/src/rbac/hooks/permissions/usePermissions.ts +15 -14
- package/src/rbac/hooks/useCan.test.ts +319 -3
- package/src/rbac/hooks/usePermissions.test.ts +426 -0
- package/src/rbac/hooks/usePermissions.ts +5 -7
- package/src/rbac/hooks/useRBAC.test.ts +1669 -2
- package/src/rbac/hooks/useRBAC.ts +7 -11
- package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
- package/src/rbac/hooks/useResolvedScope.ts +4 -1
- package/src/rbac/hooks/useResourcePermissions.test.ts +538 -1
- package/src/rbac/hooks/useResourcePermissions.ts +9 -7
- package/src/rbac/hooks/useRoleManagement.test.ts +659 -1
- package/src/rbac/hooks/useRoleManagement.ts +16 -12
- package/src/rbac/hooks/useSecureSupabase.ts +11 -12
- package/src/rbac/index.ts +32 -32
- package/src/rbac/permissions.test.ts +149 -68
- package/src/rbac/permissions.ts +0 -3
- package/src/rbac/request-deduplication.test.ts +347 -0
- package/src/rbac/secureClient.test.ts +112 -159
- package/src/rbac/secureClient.ts +46 -26
- package/src/rbac/security.test.ts +125 -44
- package/src/rbac/security.ts +7 -6
- package/src/rbac/types.test.ts +236 -0
- package/src/rbac/types.ts +7 -5
- package/src/rbac/utils/__tests__/clientSecurity.test.ts +192 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +1 -3
- package/src/rbac/utils/__tests__/deep-equal.test.ts +23 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +10 -57
- package/src/rbac/utils/clientSecurity.ts +6 -4
- package/src/rbac/utils/contextValidator.ts +1 -2
- package/src/rbac/utils/eventContext.ts +2 -2
- package/src/services/AuthService.ts +13 -11
- package/src/services/EventService.ts +4 -5
- package/src/services/OrganisationService.ts +13 -30
- package/src/services/__tests__/AuthService.edge-cases.test.ts +746 -0
- package/src/services/__tests__/AuthService.restoreSession.test.ts +23 -3
- package/src/services/__tests__/AuthService.test.ts +4 -8
- package/src/services/__tests__/BaseService.edge-cases.test.ts +506 -0
- package/src/services/__tests__/BaseService.test.ts +49 -0
- package/src/services/__tests__/EventService.edge-cases.test.ts +633 -0
- package/src/services/__tests__/EventService.eventColours.test.ts +0 -12
- package/src/services/__tests__/EventService.test.ts +0 -7
- package/src/services/__tests__/InactivityService.edge-cases.test.ts +492 -0
- package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -5
- package/src/services/__tests__/OrganisationService.edge-cases.test.ts +633 -0
- package/src/services/base/BaseService.test.ts +214 -0
- package/src/services/interfaces/IOrganisationService.ts +0 -1
- package/src/services/interfaces/__tests__/IAuthService.test.ts +190 -0
- package/src/services/interfaces/__tests__/IEventService.test.ts +176 -0
- package/src/services/interfaces/__tests__/IInactivityService.test.ts +183 -0
- package/src/services/interfaces/__tests__/IOrganisationService.test.ts +207 -0
- package/src/styles/core.css +1 -0
- package/src/theming/__tests__/runtime.test.ts +29 -94
- package/src/theming/parseEventColours.ts +18 -9
- package/src/theming/runtime.ts +1 -5
- package/src/types/__tests__/core.test.ts +397 -0
- package/src/types/__tests__/database-generated.test.ts +78 -0
- package/src/types/__tests__/file-reference.test.ts +270 -366
- package/src/types/__tests__/guards.test.ts +26 -26
- package/src/types/__tests__/index.test.ts +265 -0
- package/src/types/__tests__/type-validation.test.ts +3 -3
- package/src/types/__tests__/validation.test.ts +0 -2
- package/src/types/auth.ts +0 -1
- package/src/types/event.ts +1 -1
- package/src/types/rpc-responses.ts +33 -0
- package/src/types/supabase.ts +1 -2
- package/src/types/vitest-globals.d.ts +1 -1
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +64 -77
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +13 -0
- package/src/utils/__tests__/formatDate.unit.test.ts +1 -1
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -1
- package/src/utils/__tests__/logger.unit.test.ts +1 -1
- package/src/utils/__tests__/performanceBenchmark.test.ts +1 -2
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +48 -13
- package/src/utils/__tests__/request-deduplication.test.ts +349 -0
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -1
- package/src/utils/__tests__/timezone.test.ts +1 -1
- package/src/utils/__tests__/validation.unit.test.ts +1 -2
- package/src/utils/__tests__/validationUtils.unit.test.ts +1 -1
- package/src/utils/app/appConfig.test.ts +235 -0
- package/src/utils/app/appIdResolver.test.ts +188 -20
- package/src/utils/app/appNameResolver.test.ts +18 -10
- package/src/utils/app/appNameResolver.ts +11 -9
- package/src/utils/app/appPortMap.test.ts +125 -0
- package/src/utils/app/appPortMap.ts +51 -0
- package/src/utils/app/buildAppUrl.test.ts +273 -0
- package/src/utils/app/buildAppUrl.ts +114 -0
- package/src/utils/audit/audit.test.ts +354 -39
- package/src/utils/context/organisationContext.test.ts +10 -4
- package/src/utils/context/organisationContext.ts +5 -5
- package/src/utils/context/sessionTracking.test.ts +354 -0
- package/src/utils/core/__tests__/cn.test.ts +66 -0
- package/src/utils/core/__tests__/debugLogger.test.ts +113 -0
- package/src/utils/core/__tests__/logger.test.ts +217 -0
- package/src/utils/core/debugLogger.ts +15 -8
- package/src/utils/core/logger.ts +20 -16
- package/src/utils/device/deviceFingerprint.test.ts +8 -5
- package/src/utils/device/deviceFingerprint.ts +3 -3
- package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +185 -0
- package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +156 -0
- package/src/utils/dynamic/createLazyComponent.tsx +38 -0
- package/src/utils/dynamic/dynamicUtils.ts +6 -6
- package/src/utils/dynamic/lazyLoad.tsx +8 -36
- package/src/utils/dynamic/papaparseLoader.ts +7 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +583 -145
- package/src/utils/file-reference/index.ts +0 -1
- package/src/utils/formatting/formatDate.test.ts +22 -148
- package/src/utils/formatting/formatDateTime.test.ts +41 -119
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +40 -84
- package/src/utils/formatting/formatNumber.test.ts +259 -0
- package/src/utils/formatting/formatTime.test.ts +36 -128
- package/src/utils/formatting/formatting.ts +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +72 -3
- package/src/utils/google-places/googlePlacesUtils.ts +15 -2
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +58 -1
- package/src/utils/google-places/loadGoogleMapsScript.ts +2 -1
- package/src/utils/index.ts +52 -11
- package/src/utils/location/location.test.ts +18 -115
- package/src/utils/performance/__tests__/bundleAnalysis.test.ts +148 -0
- package/src/utils/performance/__tests__/performanceBenchmark.test.ts +251 -0
- package/src/utils/performance/__tests__/performanceBudgets.test.ts +241 -0
- package/src/utils/performance/bundleAnalysis.ts +16 -22
- package/src/utils/performance/performanceBenchmark.ts +12 -4
- package/src/utils/performance/performanceBudgets.ts +9 -6
- package/src/utils/permissions/__tests__/permissionTypes.test.ts +149 -0
- package/src/utils/permissions/permissionUtils.test.ts +20 -42
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +180 -9
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +164 -16
- package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
- package/src/utils/request-deduplication.ts +6 -4
- package/src/utils/security/auth-utils.ts +7 -7
- package/src/utils/security/secureDataAccess.test.ts +22 -191
- package/src/utils/security/secureErrors.test.ts +163 -0
- package/src/utils/security/secureStorage.test.ts +156 -0
- package/src/utils/security/secureStorage.ts +1 -1
- package/src/utils/security/security.test.ts +204 -0
- package/src/utils/security/securityMonitor.test.ts +90 -0
- package/src/utils/security/securityMonitor.ts +1 -1
- package/src/utils/storage/__tests__/config.unit.test.ts +239 -0
- package/src/utils/storage/__tests__/index.unit.test.ts +64 -12
- package/src/utils/storage/helpers.test.ts +757 -430
- package/src/utils/storage/helpers.ts +1 -2
- package/src/utils/storage/{index.ts → storageUtils.ts} +1 -36
- package/src/utils/storage/types.ts +2 -2
- package/src/utils/supabase/createBaseClient.test.ts +201 -0
- package/src/utils/supabase/createBaseClient.ts +2 -1
- package/src/utils/timezone/timezone.test.ts +25 -43
- package/src/utils/validation/__tests__/common.test.ts +115 -0
- package/src/utils/validation/__tests__/csrf.test.ts +65 -0
- package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +27 -7
- package/src/utils/validation/__tests__/passwordSchema.test.ts +164 -0
- package/src/utils/validation/__tests__/schema.test.ts +127 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +76 -3
- package/src/utils/validation/__tests__/user.test.ts +173 -0
- package/src/utils/validation/__tests__/validation.test.ts +197 -0
- package/src/utils/validation/__tests__/validationUtils.test.ts +265 -43
- package/src/utils/validation/htmlSanitization.ts +27 -31
- package/src/utils/validation/schema.ts +6 -3
- package/src/utils/validation/sqlInjectionProtection.ts +2 -2
- package/src/vite-env.d.ts +6 -0
- package/dist/DataTable-DRUIgtUH.d.ts +0 -166
- package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
- package/dist/audit-MYQXYZFU.js +0 -3
- package/dist/chunk-7ILTDCL2.js +0 -80
- package/dist/chunk-EF2UGZWY.js +0 -611
- package/dist/chunk-FEJLJNWA.js +0 -181
- package/dist/chunk-GS5672WG.js +0 -2003
- package/dist/chunk-S6ZQKDY6.js +0 -62
- package/dist/chunk-Z2FNRKF3.js +0 -994
- package/dist/useToast-AyaT-x7p.d.ts +0 -68
- package/src/components/DataTable/components/index.ts +0 -16
- package/src/components/DataTable/core/index.ts +0 -1
- package/src/components/DataTable/hooks/index.ts +0 -13
- package/src/components/DataTable/utils/index.ts +0 -10
- package/src/components/PublicLayout/index.ts +0 -32
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/public/index.ts +0 -36
- package/src/hooks/usePermissionCache.test.ts +0 -536
- package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
- package/src/rbac/audit-enhanced.ts +0 -384
- package/src/rbac/compliance/database-validator.ts +0 -165
- package/src/rbac/compliance/index.ts +0 -48
- package/src/rbac/compliance/pattern-detector.ts +0 -553
- package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
- package/src/rbac/compliance/runtime-compliance.ts +0 -99
- package/src/rbac/compliance/setup-validator.ts +0 -131
- package/src/rbac/components/index.ts +0 -26
- package/src/rbac/hooks/index.ts +0 -34
- package/src/rbac/hooks/permissions/index.ts +0 -4
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
- package/src/utils/app/appNameResolver.simple.test.ts +0 -212
- package/src/utils/google-places/index.ts +0 -26
- package/src/utils/location/index.ts +0 -16
- package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
- package/src/utils/timezone/index.ts +0 -17
- package/src/utils/validation/index.ts +0 -73
|
@@ -98,35 +98,7 @@ import { useState, useEffect, useRef, useCallback, useId, useMemo } from 'react'
|
|
|
98
98
|
import { useFocusTrap } from '../../hooks/useFocusTrap';
|
|
99
99
|
import { useSessionDraft } from '../../hooks/useSessionDraft';
|
|
100
100
|
import { deriveDialogKey } from '../../utils/persistence/keyDerivation';
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Simple debounce function that matches lodash debounce API
|
|
104
|
-
* Returns a debounced function with a cancel method
|
|
105
|
-
*/
|
|
106
|
-
function debounce<T extends (...args: any[]) => void>(
|
|
107
|
-
func: T,
|
|
108
|
-
wait: number
|
|
109
|
-
): T & { cancel: () => void } {
|
|
110
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
111
|
-
|
|
112
|
-
const debounced = ((...args: Parameters<T>) => {
|
|
113
|
-
if (timeoutId !== null) {
|
|
114
|
-
clearTimeout(timeoutId);
|
|
115
|
-
}
|
|
116
|
-
timeoutId = setTimeout(() => {
|
|
117
|
-
func(...args);
|
|
118
|
-
}, wait);
|
|
119
|
-
}) as T & { cancel: () => void };
|
|
120
|
-
|
|
121
|
-
debounced.cancel = () => {
|
|
122
|
-
if (timeoutId !== null) {
|
|
123
|
-
clearTimeout(timeoutId);
|
|
124
|
-
timeoutId = null;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
return debounced;
|
|
129
|
-
}
|
|
101
|
+
import { createLogger } from '../../utils/core/logger';
|
|
130
102
|
|
|
131
103
|
/**
|
|
132
104
|
* Dialog size variants
|
|
@@ -232,12 +204,6 @@ export interface DialogPortalProps {
|
|
|
232
204
|
children: React.ReactNode;
|
|
233
205
|
}
|
|
234
206
|
|
|
235
|
-
/**
|
|
236
|
-
* Props for the DialogClose component
|
|
237
|
-
* @public
|
|
238
|
-
*/
|
|
239
|
-
export interface DialogCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
240
|
-
|
|
241
207
|
/**
|
|
242
208
|
* Props for the DialogHeader component (semantic header element)
|
|
243
209
|
* @public
|
|
@@ -267,8 +233,6 @@ export interface DialogBodyProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
267
233
|
htmlContent?: string;
|
|
268
234
|
/** Whether to allow HTML content rendering (default: true) */
|
|
269
235
|
allowHtml?: boolean;
|
|
270
|
-
/** Whether to use strict HTML sanitization (default: true) */
|
|
271
|
-
strictSanitization?: boolean;
|
|
272
236
|
/** Whether to log HTML sanitization warnings to console (default: false) */
|
|
273
237
|
logWarnings?: boolean;
|
|
274
238
|
}
|
|
@@ -387,12 +351,13 @@ const DialogTrigger = React.forwardRef<HTMLElement, DialogTriggerProps>(
|
|
|
387
351
|
}, [onOpenChange, onClick]);
|
|
388
352
|
|
|
389
353
|
if (asChild && React.isValidElement(children)) {
|
|
390
|
-
|
|
354
|
+
const childElement = children as React.ReactElement<React.HTMLAttributes<HTMLElement>>;
|
|
355
|
+
return React.cloneElement(childElement, {
|
|
391
356
|
ref,
|
|
392
357
|
onClick: handleClick,
|
|
393
|
-
className: cn(className,
|
|
358
|
+
className: cn(className, childElement.props?.className),
|
|
394
359
|
...props,
|
|
395
|
-
});
|
|
360
|
+
} as Partial<React.HTMLAttributes<HTMLElement>>) as React.ReactElement;
|
|
396
361
|
}
|
|
397
362
|
|
|
398
363
|
return (
|
|
@@ -435,7 +400,7 @@ DialogPortal.displayName = 'DialogPortal';
|
|
|
435
400
|
* when using native dialog element which provides ::backdrop automatically
|
|
436
401
|
*/
|
|
437
402
|
const DialogOverlay = React.forwardRef<HTMLDivElement, DialogOverlayProps>(
|
|
438
|
-
({ className, ...
|
|
403
|
+
({ className: _className, ..._props }, _ref) => {
|
|
439
404
|
// Note: Native dialog element provides ::backdrop automatically
|
|
440
405
|
// This component is kept for API compatibility but may not render
|
|
441
406
|
// The native dialog's ::backdrop is styled via CSS
|
|
@@ -447,6 +412,7 @@ DialogOverlay.displayName = 'DialogOverlay';
|
|
|
447
412
|
/**
|
|
448
413
|
* Custom hook for managing smart dialog dimensions
|
|
449
414
|
* Handles responsive sizing and viewport-based constraints
|
|
415
|
+
* Dimensions are calculated synchronously based on props - no resize listener needed
|
|
450
416
|
*/
|
|
451
417
|
const useSmartDimensions = ({
|
|
452
418
|
maxHeightPercent,
|
|
@@ -455,7 +421,6 @@ const useSmartDimensions = ({
|
|
|
455
421
|
maxWidth,
|
|
456
422
|
minHeight,
|
|
457
423
|
minWidth,
|
|
458
|
-
enableScrolling = false,
|
|
459
424
|
}: {
|
|
460
425
|
maxHeightPercent?: number;
|
|
461
426
|
maxWidthPercent?: number;
|
|
@@ -463,88 +428,38 @@ const useSmartDimensions = ({
|
|
|
463
428
|
maxWidth?: string;
|
|
464
429
|
minHeight?: string;
|
|
465
430
|
minWidth?: string;
|
|
466
|
-
enableScrolling?: boolean;
|
|
467
431
|
}) => {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
432
|
+
// Calculate dimensions synchronously - no need for resize listener
|
|
433
|
+
// CSS viewport units (vh/vw) handle responsiveness automatically
|
|
434
|
+
return React.useMemo<React.CSSProperties>(() => {
|
|
435
|
+
const result: React.CSSProperties = {};
|
|
436
|
+
|
|
437
|
+
// Handle height constraints
|
|
438
|
+
if (maxHeightPercent && typeof maxHeightPercent === 'number') {
|
|
439
|
+
const constrainedHeight = Math.min(maxHeightPercent, 95);
|
|
440
|
+
result.maxHeight = `${constrainedHeight}vh`;
|
|
441
|
+
} else if (maxHeight) {
|
|
442
|
+
result.maxHeight = maxHeight;
|
|
473
443
|
}
|
|
474
444
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
} else if (maxHeight) {
|
|
483
|
-
result.maxHeight = maxHeight;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Handle width constraints
|
|
487
|
-
if (maxWidthPercent && typeof maxWidthPercent === 'number') {
|
|
488
|
-
const constrainedWidth = Math.min(maxWidthPercent, 95);
|
|
489
|
-
result.maxWidth = `${constrainedWidth}vw`;
|
|
490
|
-
} else if (maxWidth) {
|
|
491
|
-
result.maxWidth = maxWidth;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Include minHeight/minWidth if provided
|
|
495
|
-
if (minHeight) {
|
|
496
|
-
result.minHeight = minHeight;
|
|
497
|
-
}
|
|
498
|
-
if (minWidth) {
|
|
499
|
-
result.minWidth = minWidth;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
setDimensions(result);
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
// Debounced resize handler
|
|
506
|
-
const debouncedUpdate = debounce(updateDimensions, 100);
|
|
507
|
-
|
|
508
|
-
// Initial calculation
|
|
509
|
-
updateDimensions();
|
|
510
|
-
|
|
511
|
-
// Listen for resize events
|
|
512
|
-
window.addEventListener('resize', debouncedUpdate);
|
|
513
|
-
|
|
514
|
-
return () => {
|
|
515
|
-
window.removeEventListener('resize', debouncedUpdate);
|
|
516
|
-
debouncedUpdate.cancel();
|
|
517
|
-
};
|
|
518
|
-
}, [maxHeightPercent, maxWidthPercent, maxHeight, maxWidth, minHeight, minWidth, enableScrolling]);
|
|
519
|
-
|
|
520
|
-
// Return dimensions
|
|
521
|
-
const result: React.CSSProperties = {};
|
|
522
|
-
|
|
523
|
-
// Handle height constraints
|
|
524
|
-
if (maxHeightPercent && typeof maxHeightPercent === 'number') {
|
|
525
|
-
const constrainedHeight = Math.min(maxHeightPercent, 95);
|
|
526
|
-
result.maxHeight = `${constrainedHeight}vh`;
|
|
527
|
-
} else if (maxHeight) {
|
|
528
|
-
result.maxHeight = maxHeight;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Handle width constraints
|
|
532
|
-
if (maxWidthPercent && typeof maxWidthPercent === 'number') {
|
|
533
|
-
const constrainedWidth = Math.min(maxWidthPercent, 95);
|
|
534
|
-
result.maxWidth = `${constrainedWidth}vw`;
|
|
535
|
-
} else if (maxWidth) {
|
|
536
|
-
result.maxWidth = maxWidth;
|
|
537
|
-
}
|
|
445
|
+
// Handle width constraints
|
|
446
|
+
if (maxWidthPercent && typeof maxWidthPercent === 'number') {
|
|
447
|
+
const constrainedWidth = Math.min(maxWidthPercent, 95);
|
|
448
|
+
result.maxWidth = `${constrainedWidth}vw`;
|
|
449
|
+
} else if (maxWidth) {
|
|
450
|
+
result.maxWidth = maxWidth;
|
|
451
|
+
}
|
|
538
452
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
453
|
+
// Include minHeight/minWidth if provided
|
|
454
|
+
if (minHeight) {
|
|
455
|
+
result.minHeight = minHeight;
|
|
456
|
+
}
|
|
457
|
+
if (minWidth) {
|
|
458
|
+
result.minWidth = minWidth;
|
|
459
|
+
}
|
|
546
460
|
|
|
547
|
-
|
|
461
|
+
return result;
|
|
462
|
+
}, [maxHeightPercent, maxWidthPercent, maxHeight, maxWidth, minHeight, minWidth]);
|
|
548
463
|
};
|
|
549
464
|
|
|
550
465
|
/**
|
|
@@ -673,6 +588,9 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
673
588
|
const auth = useUnifiedAuth();
|
|
674
589
|
const userId = auth.user?.id || null;
|
|
675
590
|
|
|
591
|
+
// Create logger after all hooks are called (must be before any useEffects that use it)
|
|
592
|
+
const logger = createLogger('Dialog');
|
|
593
|
+
|
|
676
594
|
// Set dialog title in context for persistence
|
|
677
595
|
useEffect(() => {
|
|
678
596
|
if (setDialogTitle) {
|
|
@@ -758,7 +676,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
758
676
|
// CRITICAL: Don't auto-open if dialog was manually opened
|
|
759
677
|
// This prevents auto-open from interfering with manual opens
|
|
760
678
|
if (wasManuallyOpenedRef.current) {
|
|
761
|
-
|
|
679
|
+
logger.debug('[Dialog Persistence] ⏭️ Skipping auto-open - dialog was manually opened', {
|
|
762
680
|
persistenceKey,
|
|
763
681
|
currentOpen: open,
|
|
764
682
|
});
|
|
@@ -829,7 +747,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
829
747
|
hasAutoOpenedRef.current = true;
|
|
830
748
|
wasManuallyOpenedRef.current = false;
|
|
831
749
|
|
|
832
|
-
|
|
750
|
+
logger.debug('[Dialog] 🔄 AUTO-OPEN', { persistenceKey });
|
|
833
751
|
|
|
834
752
|
// Use small delay to prevent visual flash
|
|
835
753
|
const timeoutId = setTimeout(() => {
|
|
@@ -850,7 +768,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
850
768
|
sessionStorage.removeItem(AUTO_OPEN_LOCK_KEY);
|
|
851
769
|
};
|
|
852
770
|
}
|
|
853
|
-
}, [persistenceKey, persistOpenState, persistedOpen, open, onOpenChange, wasRestored, clearDraft]);
|
|
771
|
+
}, [persistenceKey, persistOpenState, persistedOpen, open, onOpenChange, wasRestored, clearDraft, dialogRef, userId, logger]);
|
|
854
772
|
|
|
855
773
|
// When this dialog auto-opens, clear persisted state of all other dialogs
|
|
856
774
|
// This prevents multiple dialogs from being restored simultaneously
|
|
@@ -880,7 +798,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
880
798
|
}
|
|
881
799
|
|
|
882
800
|
if (keysToRemove.length > 0) {
|
|
883
|
-
|
|
801
|
+
logger.debug('[Dialog Persistence] Clearing other dialog persisted states:', keysToRemove);
|
|
884
802
|
keysToRemove.forEach(key => sessionStorage.removeItem(key));
|
|
885
803
|
}
|
|
886
804
|
|
|
@@ -923,7 +841,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
923
841
|
|
|
924
842
|
// Only close if this dialog has persisted state (was auto-opened)
|
|
925
843
|
if (hasPersistedState) {
|
|
926
|
-
|
|
844
|
+
logger.debug('[Dialog Persistence] Closing other dialog with persisted state:', dialogPersistenceKey);
|
|
927
845
|
dialogElement.close();
|
|
928
846
|
closedCount++;
|
|
929
847
|
}
|
|
@@ -932,7 +850,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
932
850
|
}
|
|
933
851
|
});
|
|
934
852
|
if (closedCount > 0) {
|
|
935
|
-
|
|
853
|
+
logger.debug('[Dialog Persistence] Closed', closedCount, 'other dialog(s) with persisted state');
|
|
936
854
|
}
|
|
937
855
|
}
|
|
938
856
|
}, 100);
|
|
@@ -949,9 +867,9 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
949
867
|
clearTimeout(timeoutId);
|
|
950
868
|
};
|
|
951
869
|
} catch (error) {
|
|
952
|
-
|
|
870
|
+
logger.warn('[Dialog Persistence] Failed to clear other dialog states:', error);
|
|
953
871
|
}
|
|
954
|
-
}, [open, persistenceKey, persistOpenState]);
|
|
872
|
+
}, [open, persistenceKey, persistOpenState, dialogRef, logger]);
|
|
955
873
|
|
|
956
874
|
// When dialog closes (user action), immediately clear persisted state
|
|
957
875
|
// This prevents the dialog from auto-opening again after user explicitly closed it
|
|
@@ -973,16 +891,22 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
973
891
|
|
|
974
892
|
// Check lock BEFORE allowing dialog to open (synchronous check)
|
|
975
893
|
// This prevents React from even trying to open if another dialog is open
|
|
894
|
+
// Track lock acquisition state for rendering decision
|
|
895
|
+
const [lockAcquired, setLockAcquired] = React.useState(false);
|
|
896
|
+
|
|
976
897
|
useEffect(() => {
|
|
977
898
|
if (!open) {
|
|
899
|
+
setLockAcquired(false);
|
|
978
900
|
return;
|
|
979
901
|
}
|
|
980
902
|
|
|
981
903
|
// Synchronously check if we can acquire the lock
|
|
982
|
-
const
|
|
983
|
-
|
|
904
|
+
const acquired = acquireDialogLock(persistenceKey);
|
|
905
|
+
setLockAcquired(acquired);
|
|
906
|
+
|
|
907
|
+
if (!acquired) {
|
|
984
908
|
// Another dialog is open - prevent this one from opening
|
|
985
|
-
|
|
909
|
+
logger.warn('[Dialog] ⚠️ Cannot open - another dialog holds the lock', {
|
|
986
910
|
persistenceKey,
|
|
987
911
|
});
|
|
988
912
|
// Immediately close this dialog's React state
|
|
@@ -991,7 +915,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
991
915
|
}
|
|
992
916
|
|
|
993
917
|
// Lock acquired successfully - dialog can proceed to open
|
|
994
|
-
}, [open, persistenceKey, onOpenChange]);
|
|
918
|
+
}, [open, persistenceKey, onOpenChange, logger]);
|
|
995
919
|
|
|
996
920
|
// Track when dialog closes via onOpenChange to mark as closed by user
|
|
997
921
|
// This handles Cancel buttons and other programmatic closes
|
|
@@ -1021,10 +945,6 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1021
945
|
return;
|
|
1022
946
|
}
|
|
1023
947
|
|
|
1024
|
-
// Persisting open state (logging removed for performance)
|
|
1025
|
-
|
|
1026
|
-
let logTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
1027
|
-
|
|
1028
948
|
// Only persist when dialog is open
|
|
1029
949
|
if (open) {
|
|
1030
950
|
// Reset the flag when opening
|
|
@@ -1049,13 +969,6 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1049
969
|
wasManuallyOpenedRef.current = false;
|
|
1050
970
|
}
|
|
1051
971
|
}
|
|
1052
|
-
|
|
1053
|
-
// Cleanup timeout on unmount or dependency change
|
|
1054
|
-
return () => {
|
|
1055
|
-
if (logTimeoutId) {
|
|
1056
|
-
clearTimeout(logTimeoutId);
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
972
|
}, [open, persistenceKey, persistOpenState, setPersistedOpen, clearDraft]);
|
|
1060
973
|
|
|
1061
974
|
// Note: We do NOT automatically clear the draft when dialog closes
|
|
@@ -1079,8 +992,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1079
992
|
maxHeight,
|
|
1080
993
|
maxWidth,
|
|
1081
994
|
minHeight,
|
|
1082
|
-
minWidth
|
|
1083
|
-
enableScrolling
|
|
995
|
+
minWidth
|
|
1084
996
|
});
|
|
1085
997
|
|
|
1086
998
|
// Focus trap
|
|
@@ -1129,7 +1041,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1129
1041
|
isCurrent: d === dialog,
|
|
1130
1042
|
};
|
|
1131
1043
|
});
|
|
1132
|
-
|
|
1044
|
+
logger.debug('[Dialog] 🟢 OPENING', {
|
|
1133
1045
|
persistenceKey,
|
|
1134
1046
|
dialogsInDOM: dialogsBefore,
|
|
1135
1047
|
totalDialogs: allDialogsBefore.length,
|
|
@@ -1139,6 +1051,19 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1139
1051
|
// Lock was already checked in the earlier useEffect, so we can proceed
|
|
1140
1052
|
requestAnimationFrame(() => {
|
|
1141
1053
|
if (dialog && open) {
|
|
1054
|
+
// Check if dialog is connected to DOM before attempting to open
|
|
1055
|
+
if (!dialog.isConnected) {
|
|
1056
|
+
logger.warn('[Dialog] ⚠️ Dialog not connected to DOM, skipping showModal()', { persistenceKey });
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// Check if dialog is already open - if so, skip showModal() call
|
|
1061
|
+
// This prevents "Cannot call showModal() on an open non-modal dialog" error
|
|
1062
|
+
if (dialog.open) {
|
|
1063
|
+
logger.debug('[Dialog] ⏭️ Dialog already open, skipping showModal()', { persistenceKey });
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1142
1067
|
// Before opening, close any other open dialogs (safety check)
|
|
1143
1068
|
const allDialogs = document.querySelectorAll('dialog[role="dialog"]');
|
|
1144
1069
|
allDialogs.forEach((d) => {
|
|
@@ -1149,14 +1074,14 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1149
1074
|
}
|
|
1150
1075
|
});
|
|
1151
1076
|
|
|
1152
|
-
|
|
1077
|
+
logger.debug('[Dialog] ✅ showModal() called', { persistenceKey });
|
|
1153
1078
|
dialog.showModal();
|
|
1154
1079
|
}
|
|
1155
1080
|
});
|
|
1156
1081
|
} else {
|
|
1157
1082
|
// Close dialog before it's removed from DOM
|
|
1158
1083
|
if (dialog.open) {
|
|
1159
|
-
|
|
1084
|
+
logger.debug('[Dialog] 🔴 CLOSING', { persistenceKey });
|
|
1160
1085
|
dialog.close();
|
|
1161
1086
|
// Release the lock
|
|
1162
1087
|
releaseDialogLock(persistenceKey);
|
|
@@ -1173,7 +1098,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1173
1098
|
// Only close dialogs that have persistence (they might auto-open)
|
|
1174
1099
|
// Non-persistent dialogs are user-controlled and shouldn't be closed
|
|
1175
1100
|
if (otherPersistenceKey) {
|
|
1176
|
-
|
|
1101
|
+
logger.warn('[Dialog] 🗑️ Closing other persisted dialog after lock release:', {
|
|
1177
1102
|
persistenceKey,
|
|
1178
1103
|
otherPersistenceKey,
|
|
1179
1104
|
});
|
|
@@ -1185,7 +1110,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1185
1110
|
}, 50);
|
|
1186
1111
|
}
|
|
1187
1112
|
}
|
|
1188
|
-
}, [open, persistenceKey, dialogRef]);
|
|
1113
|
+
}, [open, persistenceKey, dialogRef, logger]);
|
|
1189
1114
|
|
|
1190
1115
|
// Handle close event - sync state when dialog is closed externally
|
|
1191
1116
|
// Also track when dialog is closed by user action (for persistence clearing)
|
|
@@ -1259,41 +1184,20 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1259
1184
|
|
|
1260
1185
|
const finalStyle: React.CSSProperties = { ...smartDimensions, ...style };
|
|
1261
1186
|
|
|
1187
|
+
// When maxHeightPercent is set and enableScrolling is true, set height to match
|
|
1188
|
+
// so the dialog always uses that space (not just as a max constraint)
|
|
1189
|
+
if (enableScrolling && maxHeightPercent && typeof maxHeightPercent === 'number' && !maxHeight) {
|
|
1190
|
+
const constrainedHeight = Math.min(maxHeightPercent, 95);
|
|
1191
|
+
finalStyle.height = `${constrainedHeight}vh`;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1262
1194
|
if (!maxWidth && !maxWidthPercent) {
|
|
1263
1195
|
const { maxWidth: _, ...styleWithoutMaxWidth } = finalStyle;
|
|
1264
1196
|
return styleWithoutMaxWidth;
|
|
1265
1197
|
}
|
|
1266
1198
|
|
|
1267
1199
|
return finalStyle;
|
|
1268
|
-
}, [smartDimensions, style, maxWidth, maxWidthPercent]);
|
|
1269
|
-
|
|
1270
|
-
// Track if lock has been acquired (set by useEffect when open becomes true)
|
|
1271
|
-
const [lockAcquired, setLockAcquired] = React.useState(false);
|
|
1272
|
-
|
|
1273
|
-
// Check lock BEFORE allowing dialog to open (synchronous check)
|
|
1274
|
-
// This prevents React from even trying to open if another dialog is open
|
|
1275
|
-
useEffect(() => {
|
|
1276
|
-
if (!open) {
|
|
1277
|
-
setLockAcquired(false);
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
// Synchronously check if we can acquire the lock
|
|
1282
|
-
const acquired = acquireDialogLock(persistenceKey);
|
|
1283
|
-
setLockAcquired(acquired);
|
|
1284
|
-
|
|
1285
|
-
if (!acquired) {
|
|
1286
|
-
// Another dialog is open - prevent this one from opening
|
|
1287
|
-
console.warn('[Dialog] ⚠️ Cannot open - another dialog holds the lock', {
|
|
1288
|
-
persistenceKey,
|
|
1289
|
-
});
|
|
1290
|
-
// Immediately close this dialog's React state
|
|
1291
|
-
onOpenChange?.(false);
|
|
1292
|
-
return;
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
// Lock acquired successfully - dialog can proceed to open
|
|
1296
|
-
}, [open, persistenceKey, onOpenChange]);
|
|
1200
|
+
}, [smartDimensions, style, maxWidth, maxWidthPercent, enableScrolling, maxHeight, maxHeightPercent]);
|
|
1297
1201
|
|
|
1298
1202
|
// Synchronously check if we can render (must hold lock if open)
|
|
1299
1203
|
const canRender = React.useMemo(() => {
|
|
@@ -1317,7 +1221,10 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1317
1221
|
'animate-in fade-in-0 zoom-in-95 slide-in-from-left-1/2 slide-in-from-top-[48%]',
|
|
1318
1222
|
'sm:rounded-lg',
|
|
1319
1223
|
// Reset native dialog styles
|
|
1320
|
-
'm-0 p-0 max-w-none max-h-none
|
|
1224
|
+
'm-0 p-0 max-w-none max-h-none border-0 bg-transparent outline-none',
|
|
1225
|
+
// When maxWidthPercent is set, use w-full to expand to the constraint (not w-auto)
|
|
1226
|
+
// When maxWidthPercent is not set, use w-auto to size to content
|
|
1227
|
+
(maxWidth || maxWidthPercent) ? 'w-full' : 'w-auto h-auto',
|
|
1321
1228
|
// Apply our custom styling
|
|
1322
1229
|
'border bg-background shadow-lg',
|
|
1323
1230
|
// Backdrop styling is handled via core.css only
|
|
@@ -1327,7 +1234,7 @@ const DialogContent = React.forwardRef<HTMLDialogElement, DialogContentProps>(
|
|
|
1327
1234
|
size === 'auto' && 'w-fit max-w-[90vw] sm:max-w-[80vw]',
|
|
1328
1235
|
// Layout classes: use flex when we have height constraints or enableScrolling is true
|
|
1329
1236
|
// Flex layout is needed for proper scrolling when height is constrained
|
|
1330
|
-
(enableScrolling || hasHeightConstraint) ? 'flex flex-col
|
|
1237
|
+
(enableScrolling || hasHeightConstraint) ? 'flex flex-col p-6' : 'grid p-6',
|
|
1331
1238
|
// Full screen handling
|
|
1332
1239
|
size === 'full' && 'sm:left-[50%] sm:top-[50%] sm:translate-x-[-50%] sm:translate-y-[-50%] left-0 top-0 translate-x-0 translate-y-0 h-full rounded-none sm:h-auto sm:rounded-lg',
|
|
1333
1240
|
// Overflow handling for scrolling mode or when height is constrained
|
|
@@ -1392,12 +1299,13 @@ const DialogClose = React.forwardRef<HTMLButtonElement, DialogCloseProps>(
|
|
|
1392
1299
|
}, [onOpenChange, markClosedByUser, onClick]);
|
|
1393
1300
|
|
|
1394
1301
|
if (asChild && React.isValidElement(children)) {
|
|
1395
|
-
|
|
1302
|
+
const childElement = children as React.ReactElement<React.HTMLAttributes<HTMLElement>>;
|
|
1303
|
+
return React.cloneElement(childElement, {
|
|
1396
1304
|
ref,
|
|
1397
1305
|
onClick: handleClick,
|
|
1398
|
-
className: cn(className,
|
|
1306
|
+
className: cn(className, childElement.props?.className),
|
|
1399
1307
|
...props,
|
|
1400
|
-
});
|
|
1308
|
+
} as Partial<React.HTMLAttributes<HTMLElement>>) as React.ReactElement;
|
|
1401
1309
|
}
|
|
1402
1310
|
|
|
1403
1311
|
return (
|
|
@@ -1430,8 +1338,8 @@ const DialogHeader = ({
|
|
|
1430
1338
|
}: DialogHeaderProps) => (
|
|
1431
1339
|
<header
|
|
1432
1340
|
className={cn(
|
|
1433
|
-
'flex flex-col space-y-1.5 text-center sm:text-left',
|
|
1434
|
-
sticky
|
|
1341
|
+
'flex flex-col space-y-1.5 text-center sm:text-left mb-4',
|
|
1342
|
+
sticky && 'sticky top-0 z-10 bg-background',
|
|
1435
1343
|
className
|
|
1436
1344
|
)}
|
|
1437
1345
|
{...props}
|
|
@@ -1449,7 +1357,6 @@ const DialogBody = ({
|
|
|
1449
1357
|
style,
|
|
1450
1358
|
htmlContent,
|
|
1451
1359
|
allowHtml = true,
|
|
1452
|
-
strictSanitization = true,
|
|
1453
1360
|
logWarnings = false,
|
|
1454
1361
|
children,
|
|
1455
1362
|
...props
|
|
@@ -1467,12 +1374,11 @@ const DialogBody = ({
|
|
|
1467
1374
|
}
|
|
1468
1375
|
|
|
1469
1376
|
const result = renderSafeHtml(htmlContent, {
|
|
1470
|
-
strict: strictSanitization,
|
|
1471
1377
|
logWarnings
|
|
1472
1378
|
});
|
|
1473
1379
|
|
|
1474
1380
|
return result.html;
|
|
1475
|
-
}, [htmlContent, allowHtml,
|
|
1381
|
+
}, [htmlContent, allowHtml, logWarnings]);
|
|
1476
1382
|
|
|
1477
1383
|
const hasHtmlContent = Boolean(htmlContent && allowHtml);
|
|
1478
1384
|
|
|
@@ -1510,7 +1416,7 @@ const DialogBody = ({
|
|
|
1510
1416
|
return (
|
|
1511
1417
|
<main
|
|
1512
1418
|
className={cn(
|
|
1513
|
-
'overflow-y-auto
|
|
1419
|
+
'overflow-y-auto',
|
|
1514
1420
|
// When in a flex container with height constraint, use flex properties
|
|
1515
1421
|
// so DialogBody takes up available space and only scrolls when content exceeds it
|
|
1516
1422
|
isInFlexContainer && 'flex-1 min-h-0',
|
|
@@ -1553,7 +1459,8 @@ const DialogFooter = ({
|
|
|
1553
1459
|
<footer
|
|
1554
1460
|
className={cn(
|
|
1555
1461
|
!className && 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
1556
|
-
|
|
1462
|
+
'mt-4',
|
|
1463
|
+
sticky && 'sticky bottom-0 z-10 bg-background',
|
|
1557
1464
|
className
|
|
1558
1465
|
)}
|
|
1559
1466
|
{...props}
|
|
@@ -1575,7 +1482,6 @@ const DialogTitle = React.forwardRef<HTMLHeadingElement, DialogTitleProps>(
|
|
|
1575
1482
|
}
|
|
1576
1483
|
|
|
1577
1484
|
const result = renderSafeHtml(htmlContent, {
|
|
1578
|
-
strict: true,
|
|
1579
1485
|
logWarnings: false
|
|
1580
1486
|
});
|
|
1581
1487
|
|
|
@@ -1614,7 +1520,6 @@ const DialogDescription = React.forwardRef<HTMLParagraphElement, DialogDescripti
|
|
|
1614
1520
|
}
|
|
1615
1521
|
|
|
1616
1522
|
const result = renderSafeHtml(htmlContent, {
|
|
1617
|
-
strict: true,
|
|
1618
1523
|
logWarnings: false
|
|
1619
1524
|
});
|
|
1620
1525
|
|
|
@@ -27,8 +27,9 @@ const ThrowingComponent = ({ shouldThrow = true, errorMessage = 'Test error' }:
|
|
|
27
27
|
return <div>No error</div>;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
// DelayedErrorComponent removed - not used in tests
|
|
30
31
|
// Component that throws an error after a delay
|
|
31
|
-
const
|
|
32
|
+
const _DelayedErrorComponent = ({ delay = 100 }: { delay?: number }) => {
|
|
32
33
|
const [shouldThrow, setShouldThrow] = React.useState(false);
|
|
33
34
|
|
|
34
35
|
React.useEffect(() => {
|
|
@@ -46,36 +47,6 @@ const DelayedErrorComponent = ({ delay = 100 }: { delay?: number }) => {
|
|
|
46
47
|
return <div>Loading...</div>;
|
|
47
48
|
};
|
|
48
49
|
|
|
49
|
-
// Component that recovers after retry
|
|
50
|
-
const RecoverableComponent = ({ shouldThrow = true }: { shouldThrow?: boolean }) => {
|
|
51
|
-
const [hasThrown, setHasThrown] = React.useState(false);
|
|
52
|
-
const [retryCount, setRetryCount] = React.useState(0);
|
|
53
|
-
|
|
54
|
-
React.useEffect(() => {
|
|
55
|
-
if (shouldThrow && !hasThrown && retryCount === 0) {
|
|
56
|
-
setHasThrown(true);
|
|
57
|
-
throw new Error('Recoverable error');
|
|
58
|
-
}
|
|
59
|
-
}, [shouldThrow, hasThrown, retryCount]);
|
|
60
|
-
|
|
61
|
-
// Reset when retry count changes (simulating retry)
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
if (retryCount > 0) {
|
|
64
|
-
setHasThrown(false);
|
|
65
|
-
}
|
|
66
|
-
}, [retryCount]);
|
|
67
|
-
|
|
68
|
-
// Simulate retry by incrementing retry count
|
|
69
|
-
React.useEffect(() => {
|
|
70
|
-
const timer = setTimeout(() => {
|
|
71
|
-
setRetryCount(prev => prev + 1);
|
|
72
|
-
}, 100);
|
|
73
|
-
return () => clearTimeout(timer);
|
|
74
|
-
}, []);
|
|
75
|
-
|
|
76
|
-
return <div>Recovered successfully</div>;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
50
|
describe('ErrorBoundary Component', () => {
|
|
80
51
|
let originalMode: string | undefined;
|
|
81
52
|
|
|
@@ -687,37 +658,7 @@ describe('ErrorBoundary Component', () => {
|
|
|
687
658
|
consoleSpy.mockRestore();
|
|
688
659
|
});
|
|
689
660
|
|
|
690
|
-
it('handles errors with no component name', async () => {
|
|
691
|
-
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
692
|
-
|
|
693
|
-
renderWithProviders(
|
|
694
|
-
<ErrorBoundary>
|
|
695
|
-
<ThrowingComponent />
|
|
696
|
-
</ErrorBoundary>
|
|
697
|
-
);
|
|
698
|
-
|
|
699
|
-
await waitFor(() => {
|
|
700
|
-
expect(screen.getByText('Error in Component')).toBeInTheDocument();
|
|
701
|
-
}, { interval: 10 });
|
|
702
|
-
|
|
703
|
-
consoleSpy.mockRestore();
|
|
704
|
-
});
|
|
705
661
|
|
|
706
|
-
it('handles errors with empty error message', async () => {
|
|
707
|
-
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
708
|
-
|
|
709
|
-
renderWithProviders(
|
|
710
|
-
<ErrorBoundary>
|
|
711
|
-
<ThrowingComponent errorMessage="" />
|
|
712
|
-
</ErrorBoundary>
|
|
713
|
-
);
|
|
714
|
-
|
|
715
|
-
await waitFor(() => {
|
|
716
|
-
expect(screen.getByText('An unexpected error occurred.')).toBeInTheDocument();
|
|
717
|
-
}, { interval: 10 });
|
|
718
|
-
|
|
719
|
-
consoleSpy.mockRestore();
|
|
720
|
-
});
|
|
721
662
|
});
|
|
722
663
|
|
|
723
664
|
describe('Performance and Cleanup', () => {
|
|
@@ -932,7 +873,6 @@ describe('ErrorBoundary Component', () => {
|
|
|
932
873
|
it('passes correct error information to global handler', async () => {
|
|
933
874
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
934
875
|
const globalErrorHandler = vi.fn();
|
|
935
|
-
const testError = new Error('Custom test error');
|
|
936
876
|
|
|
937
877
|
renderWithProviders(
|
|
938
878
|
<ErrorBoundaryProvider defaultErrorHandler={globalErrorHandler}>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Error Boundary Context Definition
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/ErrorBoundary
|
|
5
|
+
* @since 0.6.2
|
|
6
|
+
*
|
|
7
|
+
* Context definition for ErrorBoundary.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createContext } from 'react';
|
|
11
|
+
import type { ErrorBoundaryContextType } from './ErrorBoundaryContext.types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Context for ErrorBoundary global configuration
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export const ErrorBoundaryContext = createContext<ErrorBoundaryContextType | undefined>(undefined);
|