@jmruthers/pace-core 0.5.189 → 0.5.190
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/core-usage-manifest.json +0 -4
- package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
- package/dist/{DataTable-GUFUNZ3N.js → DataTable-ON3IXISJ.js} +8 -8
- package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-C4uxosp6.d.ts} +83 -24
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-X5NXANVI.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-I6UCQ5S6.js} +4 -2
- package/dist/{chunk-DDM4CCYT.js → chunk-4QYC5L4K.js} +60 -35
- package/dist/chunk-4QYC5L4K.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-73HSNNOQ.js} +141 -326
- package/dist/chunk-73HSNNOQ.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-DZWK57KZ.js} +2 -75
- package/dist/chunk-DZWK57KZ.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-HQVPB5MZ.js} +238 -301
- package/dist/chunk-HQVPB5MZ.js.map +1 -0
- package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
- package/dist/chunk-HW3OVDUF.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
- package/dist/chunk-I7PSE6JW.js.map +1 -0
- package/dist/{chunk-VGZZXKBR.js → chunk-J2XXC7R5.js} +280 -52
- package/dist/chunk-J2XXC7R5.js.map +1 -0
- package/dist/{chunk-UCQSRW7Z.js → chunk-NIU6J6OX.js} +425 -378
- package/dist/chunk-NIU6J6OX.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-RUYZKXOD.js} +401 -46
- package/dist/chunk-RUYZKXOD.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-SDMHPX3X.js} +176 -160
- package/dist/{chunk-2UUZZJFT.js.map → chunk-SDMHPX3X.js.map} +1 -1
- package/dist/{chunk-MX64ZF6I.js → chunk-STYK4OH2.js} +11 -11
- package/dist/chunk-STYK4OH2.js.map +1 -0
- package/dist/{chunk-YGPFYGA6.js → chunk-VVBAW5A5.js} +822 -498
- package/dist/chunk-VVBAW5A5.js.map +1 -0
- package/dist/chunk-Y4BUBBHD.js +614 -0
- package/dist/chunk-Y4BUBBHD.js.map +1 -0
- package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
- package/dist/chunk-ZSAAAMVR.js.map +1 -0
- package/dist/components.d.ts +3 -4
- package/dist/components.js +19 -19
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
- package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
- package/dist/hooks.d.ts +10 -5
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.js +79 -69
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +76 -12
- package/dist/rbac/index.js +12 -9
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-DxIDS4bC.d.ts} +16 -9
- package/dist/utils.js +16 -16
- package/docs/README.md +2 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +2 -2
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +2 -2
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +4 -4
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +21 -16
- package/docs/api/classes/StorageUtils.md +7 -4
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +20 -6
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +62 -16
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +26 -12
- package/docs/api/interfaces/FileUploadProps.md +30 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +3 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +4 -4
- package/docs/api/interfaces/StorageFileInfo.md +7 -7
- package/docs/api/interfaces/StorageFileMetadata.md +25 -14
- package/docs/api/interfaces/StorageListOptions.md +22 -9
- package/docs/api/interfaces/StorageListResult.md +4 -4
- package/docs/api/interfaces/StorageUploadOptions.md +21 -8
- package/docs/api/interfaces/StorageUploadResult.md +6 -6
- package/docs/api/interfaces/StorageUrlOptions.md +19 -6
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +151 -92
- package/docs/api-reference/components.md +15 -7
- package/docs/api-reference/providers.md +2 -2
- package/docs/api-reference/rpc-functions.md +1 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/deployment.md +8 -8
- package/docs/getting-started/examples/README.md +2 -2
- package/docs/getting-started/installation-guide.md +4 -4
- package/docs/getting-started/quick-start.md +3 -3
- package/docs/migration/MIGRATION_GUIDE.md +3 -3
- package/docs/rbac/compliance/compliance-guide.md +2 -2
- package/docs/rbac/event-based-apps.md +2 -2
- package/docs/rbac/getting-started.md +2 -2
- package/docs/rbac/quick-start.md +2 -2
- package/docs/security/README.md +4 -4
- package/docs/standards/07-rbac-and-rls-standard.md +430 -7
- package/docs/troubleshooting/README.md +2 -2
- package/docs/troubleshooting/migration.md +3 -3
- package/package.json +1 -3
- package/scripts/check-pace-core-compliance.cjs +1 -1
- package/scripts/check-pace-core-compliance.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +301 -0
- package/src/__tests__/public-recipe-view.test.ts +9 -9
- package/src/__tests__/rls-policies.test.ts +197 -61
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +1 -0
- package/src/components/Alert/Alert.test.tsx +50 -10
- package/src/components/Alert/Alert.tsx +5 -3
- package/src/components/Avatar/Avatar.test.tsx +95 -43
- package/src/components/Avatar/Avatar.tsx +16 -16
- package/src/components/Button/Button.test.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -3
- package/src/components/Calendar/Calendar.test.tsx +53 -37
- package/src/components/Calendar/Calendar.tsx +409 -82
- package/src/components/Card/Card.test.tsx +7 -4
- package/src/components/Card/Card.tsx +3 -6
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +5 -5
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
- package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
- package/src/components/DataTable/components/DataTableBody.tsx +12 -12
- package/src/components/DataTable/components/DataTableCore.tsx +3 -3
- package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
- package/src/components/DataTable/components/EditableRow.tsx +2 -2
- package/src/components/DataTable/components/EmptyState.tsx +3 -3
- package/src/components/DataTable/components/GroupHeader.tsx +2 -2
- package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +4 -4
- package/src/components/DataTable/components/LoadingState.tsx +1 -1
- package/src/components/DataTable/components/PaginationControls.tsx +11 -11
- package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
- package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
- package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/EventSelector/EventSelector.tsx +7 -7
- package/src/components/FileDisplay/FileDisplay.tsx +291 -179
- package/src/components/FileUpload/FileUpload.tsx +7 -4
- package/src/components/Header/Header.test.tsx +28 -0
- package/src/components/Header/Header.tsx +22 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +8 -8
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
- package/src/components/PaceAppLayout/test-setup.tsx +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
- package/src/components/Progress/Progress.test.tsx +18 -19
- package/src/components/Progress/Progress.tsx +31 -32
- package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
- package/src/components/Select/Select.tsx +5 -5
- package/src/components/Switch/Switch.test.tsx +2 -1
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.test.tsx +8 -2
- package/src/components/UserMenu/UserMenu.tsx +3 -3
- package/src/eslint-rules/pace-core-compliance.cjs +0 -2
- package/src/eslint-rules/pace-core-compliance.js +0 -2
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
- package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
- package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
- package/src/hooks/__tests__/{usePublicEvent.unit.test.ts → usePublicEvent.test.ts} +28 -1
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +297 -34
- package/src/hooks/useFileReference.ts +56 -11
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useInactivityTracker.ts +16 -7
- package/src/hooks/usePermissionCache.test.ts +85 -8
- package/src/hooks/useQueryCache.ts +21 -0
- package/src/hooks/useSecureDataAccess.test.ts +80 -35
- package/src/hooks/useSecureDataAccess.ts +80 -37
- package/src/providers/services/EventServiceProvider.tsx +37 -17
- package/src/providers/services/InactivityServiceProvider.tsx +4 -4
- package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
- package/src/rbac/api.ts +240 -36
- package/src/rbac/cache-invalidation.ts +21 -7
- package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
- package/src/rbac/components/NavigationGuard.tsx +23 -63
- package/src/rbac/components/NavigationProvider.test.tsx +52 -23
- package/src/rbac/components/NavigationProvider.tsx +13 -11
- package/src/rbac/components/PagePermissionGuard.tsx +77 -203
- package/src/rbac/components/PagePermissionProvider.tsx +13 -11
- package/src/rbac/components/PermissionEnforcer.tsx +24 -62
- package/src/rbac/components/RoleBasedRouter.tsx +14 -12
- package/src/rbac/components/SecureDataProvider.tsx +13 -11
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
- package/src/rbac/engine.ts +4 -2
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/useCan.test.ts +101 -53
- package/src/rbac/hooks/usePermissions.ts +108 -41
- package/src/rbac/hooks/useRBAC.test.ts +11 -3
- package/src/rbac/hooks/useRBAC.ts +83 -40
- package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
- package/src/rbac/hooks/useResolvedScope.ts +128 -70
- package/src/rbac/hooks/useSecureSupabase.ts +36 -19
- package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
- package/src/rbac/request-deduplication.ts +1 -1
- package/src/rbac/secureClient.ts +72 -12
- package/src/rbac/security.ts +29 -23
- package/src/rbac/types.ts +10 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
- package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +6 -1
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +48 -2
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +37 -2
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/types/file-reference.ts +13 -10
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +61 -33
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- package/src/utils/storage/helpers.test.ts +1 -1
- package/src/utils/storage/helpers.ts +38 -19
- package/src/utils/storage/types.ts +15 -8
- package/src/utils/validation/__tests__/csrf.test.ts +105 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
- package/src/vite-env.d.ts +2 -2
- package/dist/chunk-3GOZZZYH.js.map +0 -1
- package/dist/chunk-DDM4CCYT.js.map +0 -1
- package/dist/chunk-E7UAOUMY.js +0 -75
- package/dist/chunk-E7UAOUMY.js.map +0 -1
- package/dist/chunk-F2IMUDXZ.js.map +0 -1
- package/dist/chunk-HEHYGYOX.js.map +0 -1
- package/dist/chunk-IM4QE42D.js.map +0 -1
- package/dist/chunk-MX64ZF6I.js.map +0 -1
- package/dist/chunk-SAUPYVLF.js.map +0 -1
- package/dist/chunk-THRPYOFK.js.map +0 -1
- package/dist/chunk-UCQSRW7Z.js.map +0 -1
- package/dist/chunk-VGZZXKBR.js.map +0 -1
- package/dist/chunk-YGPFYGA6.js.map +0 -1
- package/dist/chunk-YHCN776L.js.map +0 -1
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Features:
|
|
11
11
|
* - Single, range, and multiple date selection modes
|
|
12
12
|
* - Date disabling (past dates, weekends, etc.)
|
|
13
|
-
* - Localization support
|
|
13
|
+
* - Localization support (defaults to Australian locale with Monday as first day of week)
|
|
14
14
|
* - Keyboard navigation
|
|
15
15
|
* - Accessible date selection
|
|
16
16
|
* - Customizable styling
|
|
@@ -56,22 +56,53 @@
|
|
|
56
56
|
*/
|
|
57
57
|
|
|
58
58
|
import * as React from 'react';
|
|
59
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
DayPicker,
|
|
61
|
+
type DayPickerProps,
|
|
62
|
+
useDayPicker,
|
|
63
|
+
type DayProps,
|
|
64
|
+
type MonthsProps,
|
|
65
|
+
type DateRange,
|
|
66
|
+
} from 'react-day-picker';
|
|
67
|
+
import { enAU } from 'date-fns/locale';
|
|
60
68
|
import { cn } from '../../utils/core/cn';
|
|
61
69
|
|
|
70
|
+
// Define custom types for components that don't have exported types
|
|
71
|
+
type MonthGridProps = React.TableHTMLAttributes<HTMLTableElement>;
|
|
72
|
+
type WeekdaysProps = React.HTMLAttributes<HTMLTableRowElement> & {
|
|
73
|
+
children?: React.ReactNode;
|
|
74
|
+
};
|
|
75
|
+
type MonthProps = {
|
|
76
|
+
calendarMonth: { date: Date };
|
|
77
|
+
displayIndex: number;
|
|
78
|
+
className?: string;
|
|
79
|
+
children?: React.ReactNode;
|
|
80
|
+
};
|
|
81
|
+
type RootProps = {
|
|
82
|
+
children?: React.ReactNode;
|
|
83
|
+
rootRef?: React.Ref<HTMLDivElement>;
|
|
84
|
+
className?: string;
|
|
85
|
+
style?: React.CSSProperties;
|
|
86
|
+
};
|
|
87
|
+
|
|
62
88
|
// ============================================================================
|
|
63
89
|
// CALENDAR COMPONENT
|
|
64
90
|
// ============================================================================
|
|
65
91
|
|
|
66
92
|
export interface CalendarProps extends Omit<DayPickerProps, 'className' | 'classNames' | 'styles' | 'onSelect'> {
|
|
67
93
|
/**
|
|
68
|
-
* Additional CSS classes to apply to the calendar
|
|
94
|
+
* Additional CSS classes to apply to the calendar table
|
|
69
95
|
*/
|
|
70
96
|
className?: string;
|
|
71
97
|
/**
|
|
72
98
|
* Custom classNames for DayPicker sub-components
|
|
73
99
|
*/
|
|
74
100
|
classNames?: DayPickerProps['classNames'];
|
|
101
|
+
/**
|
|
102
|
+
* Currently selected value; mirrors DayPicker's `selected` prop so callers
|
|
103
|
+
* can control the selection state.
|
|
104
|
+
*/
|
|
105
|
+
selected?: Date | Date[] | DateRange | undefined;
|
|
75
106
|
/**
|
|
76
107
|
* Date selection handler. Signature depends on mode:
|
|
77
108
|
* - mode="single": (date: Date | undefined) => void
|
|
@@ -81,18 +112,45 @@ export interface CalendarProps extends Omit<DayPickerProps, 'className' | 'class
|
|
|
81
112
|
onSelect?: ((date: Date | undefined) => void) | ((range: { from: Date; to?: Date } | undefined) => void) | ((dates: Date[]) => void);
|
|
82
113
|
}
|
|
83
114
|
|
|
115
|
+
type StoredRootProps = {
|
|
116
|
+
className?: string;
|
|
117
|
+
style?: React.CSSProperties;
|
|
118
|
+
rootRef?: React.Ref<HTMLDivElement>;
|
|
119
|
+
restProps?: React.HTMLAttributes<HTMLTableElement>;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const assignToRef = <T,>(ref: React.Ref<T | null> | undefined, value: T | null) => {
|
|
123
|
+
if (!ref) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (typeof ref === 'function') {
|
|
127
|
+
ref(value);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
(ref as React.MutableRefObject<T | null>).current = value;
|
|
131
|
+
};
|
|
132
|
+
|
|
84
133
|
/**
|
|
85
134
|
* Calendar component
|
|
86
135
|
* A flexible, accessible calendar component for date selection.
|
|
87
136
|
* Built on react-day-picker with pace-core styling.
|
|
88
137
|
*
|
|
138
|
+
* Defaults to Australian locale (en-AU) with Monday as the first day of the week.
|
|
139
|
+
* The locale can be overridden by passing a `locale` prop.
|
|
140
|
+
*
|
|
141
|
+
* Month navigation is automatically managed internally when `month` and `onMonthChange` props
|
|
142
|
+
* are not provided. The displayed month will sync with the selected date when available,
|
|
143
|
+
* or default to the current month. Navigation buttons (prev/next) work automatically.
|
|
144
|
+
*
|
|
145
|
+
* For controlled month state, pass `month` and `onMonthChange` props.
|
|
146
|
+
*
|
|
89
147
|
* @param props - Calendar configuration and styling
|
|
90
148
|
* @param ref - Forwarded ref (not used directly, but maintained for API consistency)
|
|
91
149
|
* @returns JSX.Element - The rendered calendar element
|
|
92
150
|
*
|
|
93
151
|
* @example
|
|
94
152
|
* ```tsx
|
|
95
|
-
* // Single date selection
|
|
153
|
+
* // Single date selection (uses default Australian locale)
|
|
96
154
|
* <Calendar
|
|
97
155
|
* mode="single"
|
|
98
156
|
* selected={date}
|
|
@@ -106,88 +164,357 @@ export interface CalendarProps extends Omit<DayPickerProps, 'className' | 'class
|
|
|
106
164
|
* onSelect={setDate}
|
|
107
165
|
* disabled={(date) => date < new Date()}
|
|
108
166
|
* />
|
|
167
|
+
*
|
|
168
|
+
* // Override locale (e.g., US locale with Sunday as first day)
|
|
169
|
+
* import { enUS } from 'date-fns/locale';
|
|
170
|
+
* <Calendar
|
|
171
|
+
* mode="single"
|
|
172
|
+
* selected={date}
|
|
173
|
+
* onSelect={setDate}
|
|
174
|
+
* locale={enUS}
|
|
175
|
+
* />
|
|
176
|
+
*
|
|
177
|
+
* // Controlled month state (optional - month is auto-managed if not provided)
|
|
178
|
+
* const [month, setMonth] = useState(new Date());
|
|
179
|
+
* <Calendar
|
|
180
|
+
* mode="single"
|
|
181
|
+
* selected={date}
|
|
182
|
+
* onSelect={setDate}
|
|
183
|
+
* month={month}
|
|
184
|
+
* onMonthChange={setMonth}
|
|
185
|
+
* />
|
|
109
186
|
* ```
|
|
110
187
|
*/
|
|
111
|
-
const Calendar = React.forwardRef<
|
|
112
|
-
({ className, classNames, mode, components, ...props }, ref) => {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
188
|
+
const Calendar = React.forwardRef<HTMLTableElement, CalendarProps>(
|
|
189
|
+
({ className, classNames, mode, components, locale, month: controlledMonth, onMonthChange: controlledOnMonthChange, onSelect, ...props }, ref) => {
|
|
190
|
+
const tableRef = React.useRef<HTMLTableElement | null>(null);
|
|
191
|
+
const setForwardedRef = React.useCallback(
|
|
192
|
+
(node: HTMLTableElement | null) => {
|
|
193
|
+
tableRef.current = node;
|
|
194
|
+
if (!ref) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (typeof ref === 'function') {
|
|
198
|
+
ref(node);
|
|
199
|
+
} else {
|
|
200
|
+
(ref as React.MutableRefObject<HTMLTableElement | null>).current = node;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
[ref]
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Store root props so we can re-apply them to the table element
|
|
207
|
+
const rootPropsRef = React.useRef<StoredRootProps | null>(null);
|
|
208
|
+
// Get selected from props to avoid TypeScript union type issues
|
|
209
|
+
const selected = (props as any).selected;
|
|
210
|
+
// Determine if we're in controlled or uncontrolled mode for month
|
|
211
|
+
const isMonthControlled = controlledMonth !== undefined;
|
|
212
|
+
|
|
213
|
+
// Internal state for uncontrolled month mode - always default to current month
|
|
214
|
+
const [internalMonth, setInternalMonth] = React.useState<Date>(() => {
|
|
215
|
+
const now = new Date();
|
|
216
|
+
return new Date(now.getFullYear(), now.getMonth(), 1);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Use controlled month if provided, otherwise use internal state
|
|
220
|
+
// Normalize month to first day of month to ensure consistency
|
|
221
|
+
const month = React.useMemo(() => {
|
|
222
|
+
const monthToUse = isMonthControlled ? controlledMonth : internalMonth;
|
|
223
|
+
if (!monthToUse) {
|
|
224
|
+
const now = new Date();
|
|
225
|
+
return new Date(now.getFullYear(), now.getMonth(), 1);
|
|
226
|
+
}
|
|
227
|
+
// Ensure month is normalized to first day
|
|
228
|
+
const normalized = new Date(monthToUse.getFullYear(), monthToUse.getMonth(), 1);
|
|
229
|
+
return normalized;
|
|
230
|
+
}, [isMonthControlled, controlledMonth, internalMonth]);
|
|
231
|
+
|
|
232
|
+
// Handler for month changes - must be stable reference
|
|
233
|
+
const handleMonthChange = React.useCallback((newMonth: Date) => {
|
|
234
|
+
if (!isMonthControlled) {
|
|
235
|
+
setInternalMonth(newMonth);
|
|
236
|
+
}
|
|
237
|
+
controlledOnMonthChange?.(newMonth);
|
|
238
|
+
}, [isMonthControlled, controlledOnMonthChange]);
|
|
239
|
+
|
|
240
|
+
// Create a wrapped handler to ensure it's always a function
|
|
241
|
+
const wrappedHandleMonthChange = React.useCallback((newMonth: Date) => {
|
|
242
|
+
handleMonthChange(newMonth);
|
|
243
|
+
}, [handleMonthChange]);
|
|
244
|
+
|
|
245
|
+
// Removed mount logging - was for debugging only
|
|
246
|
+
|
|
247
|
+
// Custom Root: capture provided props so we can attach them to the table directly
|
|
248
|
+
const CustomRoot = React.memo(({ children, rootRef: dayPickerRootRef, ...rootProps }: RootProps) => {
|
|
249
|
+
const {
|
|
250
|
+
className: rootClassName,
|
|
251
|
+
style: rootStyle,
|
|
252
|
+
children: _ignoredChildren,
|
|
253
|
+
...restProps
|
|
254
|
+
} = rootProps as React.HTMLAttributes<HTMLDivElement> & { children?: React.ReactNode };
|
|
255
|
+
|
|
256
|
+
rootPropsRef.current = {
|
|
257
|
+
className: rootClassName,
|
|
258
|
+
style: rootStyle as React.CSSProperties | undefined,
|
|
259
|
+
rootRef: dayPickerRootRef,
|
|
260
|
+
restProps: restProps as React.HTMLAttributes<HTMLTableElement>,
|
|
261
|
+
};
|
|
262
|
+
return <>{children}</>;
|
|
263
|
+
});
|
|
264
|
+
CustomRoot.displayName = 'CustomRoot';
|
|
265
|
+
|
|
266
|
+
// Custom Months: Remove wrapper div, return children directly
|
|
267
|
+
const CustomMonths = React.memo(({ children }: MonthsProps) => {
|
|
268
|
+
return <>{children}</>;
|
|
269
|
+
});
|
|
270
|
+
CustomMonths.displayName = 'CustomMonths';
|
|
271
|
+
|
|
272
|
+
const CustomMonthGrid = React.forwardRef<HTMLTableElement, MonthGridProps>((props, forwardedRef) => {
|
|
273
|
+
return <table ref={forwardedRef} {...props} />;
|
|
274
|
+
});
|
|
275
|
+
CustomMonthGrid.displayName = 'CustomMonthGrid';
|
|
276
|
+
|
|
277
|
+
// Custom Month: inject caption + navigation directly inside the <table>
|
|
278
|
+
const CustomMonth = React.memo(({ calendarMonth, displayIndex, className, children }: MonthProps) => {
|
|
279
|
+
const { formatters, components, labels, classNames, previousMonth, nextMonth, goToMonth } = useDayPicker();
|
|
280
|
+
const caption = formatters.formatCaption(calendarMonth.date, {});
|
|
281
|
+
const Chevron = components?.Chevron;
|
|
282
|
+
|
|
283
|
+
const childrenArray = React.Children.toArray(children);
|
|
284
|
+
const monthGridIndex = childrenArray.findIndex((child: any) => {
|
|
285
|
+
if (!React.isValidElement(child)) return false;
|
|
286
|
+
const childType = child.type as any;
|
|
287
|
+
return (typeof childType === 'function' && childType.displayName === 'MonthGrid') ||
|
|
288
|
+
child.type === 'table';
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
return (
|
|
292
|
+
<>
|
|
293
|
+
{childrenArray.map((child, index) => {
|
|
294
|
+
if (React.isValidElement(child) && (child.type as any)?.displayName === 'MonthCaption') {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (index === monthGridIndex && React.isValidElement(child)) {
|
|
299
|
+
const monthGridChild = child as React.ReactElement<MonthGridProps>;
|
|
300
|
+
const applyRootProps = displayIndex === 0 && index === monthGridIndex;
|
|
301
|
+
const storedRootProps = applyRootProps ? rootPropsRef.current : null;
|
|
302
|
+
|
|
303
|
+
const { children: monthGridChildren, className: monthGridClassName, style: monthGridStyle, ...monthGridRest } =
|
|
304
|
+
monthGridChild.props as React.TableHTMLAttributes<HTMLTableElement>;
|
|
305
|
+
|
|
306
|
+
const mergedClassName = cn(
|
|
307
|
+
'w-full border-collapse rounded-md border border-sec-200 bg-background',
|
|
308
|
+
applyRootProps ? storedRootProps?.className : undefined,
|
|
309
|
+
className,
|
|
310
|
+
monthGridClassName
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const mergedStyle = {
|
|
314
|
+
...(applyRootProps ? storedRootProps?.style ?? {} : {}),
|
|
315
|
+
...(monthGridStyle ?? {}),
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const tableProps: React.TableHTMLAttributes<HTMLTableElement> = {
|
|
319
|
+
...(applyRootProps && storedRootProps?.restProps ? storedRootProps.restProps : {}),
|
|
320
|
+
...monthGridRest,
|
|
321
|
+
className: mergedClassName,
|
|
322
|
+
...(Object.keys(mergedStyle).length ? { style: mergedStyle } : {}),
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
if (mode && (tableProps as Record<string, unknown>)['data-mode'] === undefined) {
|
|
326
|
+
(tableProps as Record<string, unknown>)['data-mode'] = mode;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const shouldAttachRef = applyRootProps || storedRootProps?.rootRef;
|
|
330
|
+
const handleTableRef = shouldAttachRef
|
|
331
|
+
? (node: HTMLTableElement | null) => {
|
|
332
|
+
if (applyRootProps) {
|
|
333
|
+
setForwardedRef(node);
|
|
334
|
+
}
|
|
335
|
+
if (storedRootProps?.rootRef) {
|
|
336
|
+
assignToRef(storedRootProps.rootRef as React.Ref<HTMLTableElement | null>, node);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
: undefined;
|
|
340
|
+
|
|
341
|
+
const handlePreviousClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
if (!previousMonth) return;
|
|
344
|
+
goToMonth(previousMonth);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const handleNextClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
348
|
+
event.preventDefault();
|
|
349
|
+
if (!nextMonth) return;
|
|
350
|
+
goToMonth(nextMonth);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const monthGridElement = monthGridChild as React.ReactElement & {
|
|
354
|
+
ref?: React.Ref<HTMLTableElement | null>;
|
|
355
|
+
};
|
|
356
|
+
const mergedRef =
|
|
357
|
+
handleTableRef || monthGridElement.ref
|
|
358
|
+
? (node: HTMLTableElement | null) => {
|
|
359
|
+
if (handleTableRef) {
|
|
360
|
+
handleTableRef(node);
|
|
361
|
+
}
|
|
362
|
+
assignToRef(monthGridElement.ref as React.Ref<HTMLTableElement | null> | undefined, node);
|
|
363
|
+
}
|
|
364
|
+
: undefined;
|
|
365
|
+
|
|
366
|
+
return React.cloneElement(
|
|
367
|
+
monthGridElement,
|
|
368
|
+
{
|
|
369
|
+
key: child.key ?? `month-grid-${displayIndex}`,
|
|
370
|
+
...tableProps,
|
|
371
|
+
...(mergedRef ? { ref: mergedRef } : {}),
|
|
372
|
+
},
|
|
373
|
+
<>
|
|
374
|
+
<caption className="relative">
|
|
375
|
+
<nav className="relative flex items-center justify-center gap-1">
|
|
376
|
+
<button
|
|
377
|
+
type="button"
|
|
378
|
+
className={cn(
|
|
379
|
+
'h-7 w-7 bg-transparent p-0',
|
|
380
|
+
'inline-flex items-center justify-center rounded-md',
|
|
381
|
+
'hover:bg-acc-100',
|
|
382
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',
|
|
383
|
+
'disabled:opacity-50 disabled:pointer-events-none',
|
|
384
|
+
classNames?.button_previous
|
|
385
|
+
)}
|
|
386
|
+
tabIndex={previousMonth ? undefined : -1}
|
|
387
|
+
aria-disabled={previousMonth ? undefined : true}
|
|
388
|
+
aria-label={previousMonth ? labels.labelPrevious(previousMonth) : undefined}
|
|
389
|
+
onClick={handlePreviousClick}
|
|
390
|
+
disabled={!previousMonth}
|
|
391
|
+
>
|
|
392
|
+
{Chevron ? <Chevron orientation="left" className="size-4" disabled={!previousMonth} /> : <span>‹</span>}
|
|
393
|
+
</button>
|
|
394
|
+
<span className="text-sm font-medium">{caption}</span>
|
|
395
|
+
<button
|
|
396
|
+
type="button"
|
|
397
|
+
className={cn(
|
|
398
|
+
'h-7 w-7 bg-transparent p-0',
|
|
399
|
+
'inline-flex items-center justify-center rounded-md',
|
|
400
|
+
'hover:bg-acc-100',
|
|
401
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',
|
|
402
|
+
'disabled:opacity-50 disabled:pointer-events-none',
|
|
403
|
+
classNames?.button_next
|
|
404
|
+
)}
|
|
405
|
+
tabIndex={nextMonth ? undefined : -1}
|
|
406
|
+
aria-disabled={nextMonth ? undefined : true}
|
|
407
|
+
aria-label={nextMonth ? labels.labelNext(nextMonth) : undefined}
|
|
408
|
+
onClick={handleNextClick}
|
|
409
|
+
disabled={!nextMonth}
|
|
410
|
+
>
|
|
411
|
+
{Chevron ? <Chevron orientation="right" className="size-4" disabled={!nextMonth} /> : <span>›</span>}
|
|
412
|
+
</button>
|
|
413
|
+
</nav>
|
|
414
|
+
</caption>
|
|
415
|
+
{monthGridChildren}
|
|
416
|
+
</>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return child;
|
|
421
|
+
})}
|
|
422
|
+
</>
|
|
423
|
+
);
|
|
424
|
+
});
|
|
425
|
+
CustomMonth.displayName = 'CustomMonth';
|
|
426
|
+
|
|
427
|
+
// Custom Weekdays: render table head with semantic row
|
|
428
|
+
const CustomWeekdays = React.memo(({ className, children, ...props }: WeekdaysProps) => {
|
|
429
|
+
return (
|
|
430
|
+
<thead>
|
|
431
|
+
<tr className={cn('text-xs text-sec-500', className)} {...props}>
|
|
432
|
+
{children}
|
|
433
|
+
</tr>
|
|
434
|
+
</thead>
|
|
435
|
+
);
|
|
436
|
+
});
|
|
437
|
+
CustomWeekdays.displayName = 'CustomWeekdays';
|
|
438
|
+
|
|
439
|
+
// Memoize components to ensure stable references
|
|
440
|
+
const defaultComponents = React.useMemo(() => ({
|
|
441
|
+
Root: CustomRoot,
|
|
442
|
+
Months: CustomMonths,
|
|
443
|
+
Month: CustomMonth,
|
|
444
|
+
MonthGrid: CustomMonthGrid,
|
|
445
|
+
// MonthCaption is now handled inside CustomMonth (injected into table)
|
|
446
|
+
Weekdays: CustomWeekdays,
|
|
447
|
+
// Spread user components AFTER ours so ours take precedence
|
|
448
|
+
...(components || {}),
|
|
449
|
+
}), [components, CustomRoot, CustomMonths, CustomMonth, CustomWeekdays]);
|
|
146
450
|
|
|
147
451
|
return (
|
|
148
|
-
<
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
452
|
+
<DayPicker
|
|
453
|
+
{...(mode ? { mode } : {})}
|
|
454
|
+
locale={locale ?? enAU}
|
|
455
|
+
hideNavigation={true}
|
|
456
|
+
{...(props as any)}
|
|
457
|
+
// CRITICAL: Explicit props must come AFTER spread to ensure they override any props from spread
|
|
458
|
+
// This ensures month, onMonthChange, selected, and onSelect are always correct
|
|
459
|
+
selected={selected}
|
|
460
|
+
onSelect={onSelect}
|
|
461
|
+
month={month}
|
|
462
|
+
onMonthChange={wrappedHandleMonthChange}
|
|
463
|
+
className={className}
|
|
464
|
+
classNames={{
|
|
465
|
+
// v9 API: Updated for table-based structure
|
|
466
|
+
months: '', // No wrapper - removed by CustomMonths
|
|
467
|
+
month: '', // No wrapper - removed by CustomMonth
|
|
468
|
+
month_caption: '', // Now handled by custom component (renders as <caption>)
|
|
469
|
+
caption_label: 'text-sm font-medium',
|
|
470
|
+
nav: 'relative flex items-center justify-center space-x-1',
|
|
471
|
+
// v9: button_previous and button_next for navigation buttons
|
|
472
|
+
button_previous: cn(
|
|
473
|
+
'absolute left-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
|
474
|
+
'border border-input hover:bg-acc-100',
|
|
475
|
+
'inline-flex items-center justify-center rounded-md',
|
|
476
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'
|
|
477
|
+
),
|
|
478
|
+
button_next: cn(
|
|
479
|
+
'absolute right-1 h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
|
480
|
+
'border border-input hover:bg-acc-100',
|
|
481
|
+
'inline-flex items-center justify-center rounded-md',
|
|
482
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2'
|
|
483
|
+
),
|
|
484
|
+
// v9: table -> month_grid (now a proper <table>)
|
|
485
|
+
month_grid: '', // Styles applied directly to table in CustomMonth
|
|
486
|
+
// v9: head_row -> weekdays (now wrapped in <thead> by custom component)
|
|
487
|
+
weekdays: '', // Styles applied to <tr> inside <thead>
|
|
488
|
+
weekday: 'text-sec-600 rounded-md w-9 font-normal text-[0.8rem]',
|
|
489
|
+
// v9: row -> week (now a proper <tr>)
|
|
490
|
+
week: 'mt-2',
|
|
491
|
+
// v9: cell -> day (now a proper <td> by custom component)
|
|
492
|
+
day: '', // Styles moved to <td> in custom component
|
|
493
|
+
// v9: day -> day_button (the button inside the cell)
|
|
494
|
+
day_button: cn(
|
|
495
|
+
'h-9 w-9 p-0 font-normal aria-selected:opacity-100',
|
|
496
|
+
'hover:bg-acc-100 hover:text-main-600',
|
|
497
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main-600 focus-visible:ring-offset-2',
|
|
498
|
+
'inline-flex items-center justify-center rounded-md'
|
|
499
|
+
),
|
|
500
|
+
// v9: day_range_end -> range_end
|
|
501
|
+
range_end: 'range-end',
|
|
502
|
+
// v9: day_selected -> selected
|
|
503
|
+
selected: 'bg-main-600 text-main-50 hover:bg-main-600 hover:text-main-50 focus:bg-main-600 focus:text-main-50',
|
|
504
|
+
// v9: day_today -> today
|
|
505
|
+
today: 'bg-sec-100 text-main-600 font-semibold',
|
|
506
|
+
// v9: day_outside -> outside
|
|
507
|
+
outside: 'outside text-sec-400 opacity-50 aria-selected:bg-acc-50/50 aria-selected:text-sec-400 aria-selected:opacity-30',
|
|
508
|
+
// v9: day_disabled -> disabled
|
|
509
|
+
disabled: 'text-sec-400 opacity-50 cursor-not-allowed',
|
|
510
|
+
// v9: day_range_middle -> range_middle
|
|
511
|
+
range_middle: 'aria-selected:bg-acc-100 aria-selected:text-main-600',
|
|
512
|
+
// v9: day_hidden -> hidden
|
|
513
|
+
hidden: 'invisible',
|
|
514
|
+
...classNames,
|
|
515
|
+
}}
|
|
516
|
+
components={defaultComponents}
|
|
517
|
+
/>
|
|
191
518
|
);
|
|
192
519
|
}
|
|
193
520
|
);
|
|
@@ -146,7 +146,8 @@ describe('Card Component Suite', () => {
|
|
|
146
146
|
it('has proper semantic structure', () => {
|
|
147
147
|
renderWithProviders(<CardHeader>Header content</CardHeader>);
|
|
148
148
|
const header = screen.getByRole('banner');
|
|
149
|
-
expect(header).
|
|
149
|
+
expect(header.tagName).toBe('HEADER');
|
|
150
|
+
expect(header).toHaveClass('p-6', 'min-w-0', 'w-full');
|
|
150
151
|
});
|
|
151
152
|
});
|
|
152
153
|
});
|
|
@@ -172,10 +173,11 @@ describe('Card Component Suite', () => {
|
|
|
172
173
|
expect(ref.current).toBeInstanceOf(HTMLHeadingElement);
|
|
173
174
|
});
|
|
174
175
|
|
|
175
|
-
it('
|
|
176
|
+
it('uses semantic heading element', () => {
|
|
176
177
|
renderWithProviders(<CardTitle>Card Title</CardTitle>);
|
|
177
178
|
const title = screen.getByRole('heading', { level: 3 });
|
|
178
|
-
expect(title).
|
|
179
|
+
expect(title.tagName).toBe('H3');
|
|
180
|
+
expect(title.className).toBe('');
|
|
179
181
|
});
|
|
180
182
|
});
|
|
181
183
|
});
|
|
@@ -256,7 +258,8 @@ describe('Card Component Suite', () => {
|
|
|
256
258
|
it('has proper semantic structure', () => {
|
|
257
259
|
renderWithProviders(<CardFooter>Footer content</CardFooter>);
|
|
258
260
|
const footer = screen.getByRole('contentinfo');
|
|
259
|
-
expect(footer).
|
|
261
|
+
expect(footer.tagName).toBe('FOOTER');
|
|
262
|
+
expect(footer).toHaveClass('p-6', 'pt-0', 'min-w-0', 'w-full');
|
|
260
263
|
});
|
|
261
264
|
});
|
|
262
265
|
});
|
|
@@ -191,7 +191,7 @@ const CardHeader = React.forwardRef<
|
|
|
191
191
|
>(({ className, ...props }, ref) => (
|
|
192
192
|
<header
|
|
193
193
|
ref={ref}
|
|
194
|
-
className={cn("
|
|
194
|
+
className={cn("p-6 min-w-0 w-full", className)}
|
|
195
195
|
{...props}
|
|
196
196
|
/>
|
|
197
197
|
))
|
|
@@ -203,10 +203,7 @@ const CardTitle = React.forwardRef<
|
|
|
203
203
|
>(({ className, ...props }, ref) => (
|
|
204
204
|
<h3
|
|
205
205
|
ref={ref}
|
|
206
|
-
className={cn(
|
|
207
|
-
'text-2xl font-semibold leading-none tracking-tight',
|
|
208
|
-
className
|
|
209
|
-
)}
|
|
206
|
+
className={cn(className)}
|
|
210
207
|
{...props}
|
|
211
208
|
/>
|
|
212
209
|
))
|
|
@@ -242,7 +239,7 @@ const CardFooter = React.forwardRef<
|
|
|
242
239
|
>(({ className, ...props }, ref) => (
|
|
243
240
|
<footer
|
|
244
241
|
ref={ref}
|
|
245
|
-
className={cn("
|
|
242
|
+
className={cn("p-6 pt-0 min-w-0 w-full", className)}
|
|
246
243
|
{...props}
|
|
247
244
|
/>
|
|
248
245
|
))
|
|
@@ -58,7 +58,7 @@ const Checkbox = React.forwardRef<
|
|
|
58
58
|
<CheckboxPrimitive.Root
|
|
59
59
|
ref={ref}
|
|
60
60
|
className={cn(
|
|
61
|
-
"peer
|
|
61
|
+
"peer size-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
62
62
|
className
|
|
63
63
|
)}
|
|
64
64
|
{...props}
|
|
@@ -66,7 +66,7 @@ const Checkbox = React.forwardRef<
|
|
|
66
66
|
<CheckboxPrimitive.Indicator
|
|
67
67
|
className={cn("flex items-center justify-center text-current")}
|
|
68
68
|
>
|
|
69
|
-
<Check className="
|
|
69
|
+
<Check className="size-4" />
|
|
70
70
|
</CheckboxPrimitive.Indicator>
|
|
71
71
|
</CheckboxPrimitive.Root>
|
|
72
72
|
))
|
|
@@ -136,9 +136,9 @@ function ActionButtonsComponent<TData extends DataRecord = DataRecord>({
|
|
|
136
136
|
aria-disabled={isDisabled}
|
|
137
137
|
data-testid={action.testId}
|
|
138
138
|
aria-label={label}
|
|
139
|
-
className="
|
|
139
|
+
className="size-8 p-0"
|
|
140
140
|
>
|
|
141
|
-
{Icon && <Icon className="
|
|
141
|
+
{Icon && <Icon className="size-4" />}
|
|
142
142
|
</Button>
|
|
143
143
|
);
|
|
144
144
|
})}
|
|
@@ -149,9 +149,9 @@ function ActionButtonsComponent<TData extends DataRecord = DataRecord>({
|
|
|
149
149
|
return (
|
|
150
150
|
<Select>
|
|
151
151
|
<SelectTrigger asChild>
|
|
152
|
-
<Button variant="ghost" className="
|
|
152
|
+
<Button variant="ghost" className="size-8 p-0">
|
|
153
153
|
<span className="sr-only">Open menu</span>
|
|
154
|
-
<MoreHorizontal className="
|
|
154
|
+
<MoreHorizontal className="size-4" />
|
|
155
155
|
</Button>
|
|
156
156
|
</SelectTrigger>
|
|
157
157
|
<SelectContent className="!bg-main-50 border border-sec-200 shadow-lg z-[9999]" style={{ backgroundColor: 'white' }}>
|
|
@@ -172,7 +172,7 @@ function ActionButtonsComponent<TData extends DataRecord = DataRecord>({
|
|
|
172
172
|
className="flex items-center gap-2"
|
|
173
173
|
aria-disabled={isDisabled}
|
|
174
174
|
>
|
|
175
|
-
{Icon && <Icon className="
|
|
175
|
+
{Icon && <Icon className="size-4" />}
|
|
176
176
|
<span>{label}</span>
|
|
177
177
|
</SelectItem>
|
|
178
178
|
);
|