@jmruthers/pace-core 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -10
- package/cursor-rules/00-pace-core-compliance.mdc +18 -91
- package/cursor-rules/01-standards-compliance.mdc +16 -47
- package/cursor-rules/02-project-structure.mdc +4 -4
- package/cursor-rules/03-solid-principles.mdc +45 -164
- package/cursor-rules/04-testing-standards.mdc +22 -69
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
- package/cursor-rules/06-code-quality.mdc +42 -125
- package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
- package/cursor-rules/08-markup-quality.mdc +452 -0
- package/cursor-rules/CHANGELOG.md +18 -0
- package/cursor-rules/README.md +2 -1
- package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
- package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
- package/dist/{DataTable-DQ7RSOHE.js → DataTable-TPTKCX4D.js} +10 -9
- package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +356 -111
- package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
- package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
- package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
- package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
- package/dist/chunk-24UVZUZG.js.map +1 -0
- package/dist/{chunk-4N5C5XZU.js → chunk-2UOI2FG5.js} +4 -4
- package/dist/chunk-2UOI2FG5.js.map +1 -0
- package/dist/{chunk-T33XF5ZC.js → chunk-3XC4CPTD.js} +4317 -3963
- package/dist/chunk-3XC4CPTD.js.map +1 -0
- package/dist/{chunk-4ZC4GX36.js → chunk-6J4GEEJR.js} +172 -45
- package/dist/chunk-6J4GEEJR.js.map +1 -0
- package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
- package/dist/chunk-6SOIHG6Z.js.map +1 -0
- package/dist/{chunk-BYFSK72L.js → chunk-EHMR7VYL.js} +4 -4
- package/dist/chunk-EHMR7VYL.js.map +1 -0
- package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
- package/dist/chunk-F2IMUDXZ.js.map +1 -0
- package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
- package/dist/chunk-FFQEQTNW.js.map +1 -0
- package/dist/chunk-FMUCXFII.js +76 -0
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
- package/dist/chunk-L4OXEN46.js.map +1 -0
- package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
- package/dist/chunk-M43Y4SSO.js.map +1 -0
- package/dist/{chunk-3XTALGJF.js → chunk-MMZ7JXPU.js} +60 -223
- package/dist/chunk-MMZ7JXPU.js.map +1 -0
- package/dist/{chunk-GLK6VM3F.js → chunk-NECFR5MM.js} +254 -170
- package/dist/chunk-NECFR5MM.js.map +1 -0
- package/dist/{chunk-JBKQ3SAO.js → chunk-SFZUDBL5.js} +40 -4
- package/dist/chunk-SFZUDBL5.js.map +1 -0
- package/dist/{chunk-XM25TVIE.js → chunk-XWQCNGTQ.js} +724 -363
- package/dist/chunk-XWQCNGTQ.js.map +1 -0
- package/dist/components.d.ts +5 -5
- package/dist/components.js +14 -11
- package/dist/components.js.map +1 -1
- package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
- package/dist/hooks.d.ts +55 -122
- package/dist/hooks.js +8 -12
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +60 -13
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +21 -3
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +145 -114
- package/dist/rbac/index.js +8 -11
- package/dist/theming/runtime.d.ts +1 -13
- package/dist/theming/runtime.js +1 -1
- package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
- package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
- package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
- package/dist/types.d.ts +2 -2
- package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +31 -1
- package/dist/utils.d.ts +4 -5
- package/dist/utils.js +14 -14
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +7 -1
- package/docs/api/classes/ColumnFactory.md +8 -8
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +4 -4
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- package/docs/api/classes/SecureSupabaseClient.md +18 -15
- package/docs/api/classes/StorageUtils.md +1 -1
- 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 +4 -4
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +9 -2
- package/docs/api/interfaces/ButtonProps.md +7 -4
- package/docs/api/interfaces/CalendarProps.md +8 -5
- package/docs/api/interfaces/CardProps.md +8 -5
- 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 +24 -21
- package/docs/api/interfaces/DataTableColumn.md +31 -31
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
- package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
- package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +8 -8
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +26 -23
- package/docs/api/interfaces/FooterProps.md +10 -8
- package/docs/api/interfaces/FormFieldProps.md +10 -10
- 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 +7 -4
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +14 -11
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +11 -11
- package/docs/api/interfaces/NavigationMenuProps.md +15 -15
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- 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 +30 -27
- package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
- package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
- package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
- package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
- 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 +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- 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 +3 -3
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- 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 +3 -3
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +4 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +14 -11
- package/docs/api/interfaces/UserMenuProps.md +8 -6
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +575 -634
- package/docs/architecture/database-schema-requirements.md +161 -0
- package/docs/core-concepts/rbac-system.md +3 -3
- package/docs/documentation-index.md +2 -4
- package/docs/getting-started/cursor-rules.md +2 -1
- package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
- package/docs/migration/MIGRATION_GUIDE.md +2 -24
- package/docs/migration/README.md +52 -6
- package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
- package/docs/migration/database-changes-december-2025.md +3 -3
- package/docs/rbac/event-based-apps.md +1 -1
- package/docs/rbac/getting-started.md +1 -1
- package/docs/rbac/quick-start.md +1 -1
- package/docs/standards/README.md +1 -0
- package/package.json +2 -1
- package/scripts/audit/core/checks/accessibility.cjs +197 -0
- package/scripts/audit/core/checks/api-usage.cjs +191 -0
- package/scripts/audit/core/checks/bundle.cjs +142 -0
- package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +714 -687
- package/scripts/audit/core/checks/config.cjs +54 -0
- package/scripts/audit/core/checks/coverage.cjs +84 -0
- package/scripts/audit/core/checks/dependencies.cjs +454 -0
- package/scripts/audit/core/checks/documentation.cjs +203 -0
- package/scripts/audit/core/checks/environment.cjs +128 -0
- package/scripts/audit/core/checks/error-handling.cjs +299 -0
- package/scripts/audit/core/checks/forms.cjs +172 -0
- package/scripts/audit/core/checks/heuristics.cjs +68 -0
- package/scripts/audit/core/checks/hooks.cjs +334 -0
- package/scripts/audit/core/checks/imports.cjs +244 -0
- package/scripts/audit/core/checks/performance.cjs +325 -0
- package/scripts/audit/core/checks/routes.cjs +117 -0
- package/scripts/audit/core/checks/state.cjs +130 -0
- package/scripts/audit/core/checks/structure.cjs +65 -0
- package/scripts/audit/core/checks/style.cjs +584 -0
- package/scripts/audit/core/checks/testing.cjs +122 -0
- package/scripts/audit/core/checks/typescript.cjs +61 -0
- package/scripts/audit/core/scanner.cjs +199 -0
- package/scripts/audit/core/utils.cjs +137 -0
- package/scripts/audit/index.cjs +223 -0
- package/scripts/audit/reporters/console.cjs +151 -0
- package/scripts/audit/reporters/json.cjs +54 -0
- package/scripts/audit/reporters/markdown.cjs +124 -0
- package/scripts/audit-consuming-app.cjs +61 -936
- package/scripts/build-docs/build-decision.js +240 -0
- package/scripts/build-docs/cache-utils.js +105 -0
- package/scripts/build-docs/content-normalization.js +150 -0
- package/scripts/build-docs/file-utils.js +105 -0
- package/scripts/build-docs/git-utils.js +86 -0
- package/scripts/build-docs/hash-utils.js +116 -0
- package/scripts/build-docs/typedoc-runner.js +220 -0
- package/scripts/build-docs-incremental.js +77 -913
- package/scripts/utils/command-runner.js +16 -11
- package/scripts/validate-formats.js +61 -56
- package/scripts/validate-master.js +74 -69
- package/scripts/validate-pre-publish.js +70 -65
- package/src/__tests__/hooks/usePermissions.test.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +12 -18
- package/src/components/Alert/Alert.tsx +5 -7
- package/src/components/Avatar/Avatar.test.tsx +4 -4
- package/src/components/Badge/Badge.tsx +14 -0
- package/src/components/Button/Button.tsx +22 -0
- package/src/components/Calendar/Calendar.tsx +8 -2
- package/src/components/Card/Card.tsx +4 -0
- package/src/components/Checkbox/Checkbox.test.tsx +12 -12
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/DataTable.tsx +38 -4
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
- package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
- package/src/components/DataTable/components/ActionButtons.tsx +10 -7
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
- package/src/components/DataTable/components/DataTableBody.tsx +8 -0
- package/src/components/DataTable/components/DataTableCore.tsx +196 -554
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
- package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
- package/src/components/DataTable/components/DataTableModals.tsx +8 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
- package/src/components/DataTable/components/EditFields.tsx +307 -0
- package/src/components/DataTable/components/EditableRow.tsx +8 -0
- package/src/components/DataTable/components/EmptyState.tsx +10 -0
- package/src/components/DataTable/components/FilterRow.tsx +12 -0
- package/src/components/DataTable/components/GroupHeader.tsx +12 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
- package/src/components/DataTable/components/ImportModal.tsx +7 -0
- package/src/components/DataTable/components/LoadingState.tsx +6 -0
- package/src/components/DataTable/components/PaginationControls.tsx +16 -1
- package/src/components/DataTable/components/RowComponent.tsx +391 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +61 -849
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
- package/src/components/DataTable/components/cellValueUtils.ts +40 -0
- package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
- package/src/components/DataTable/context/DataTableContext.tsx +50 -0
- package/src/components/DataTable/core/ColumnFactory.ts +31 -0
- package/src/components/DataTable/core/DataTableContext.tsx +32 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
- package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
- package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
- package/src/components/DataTable/styles.ts +6 -6
- package/src/components/DataTable/types.ts +6 -10
- package/src/components/DataTable/utils/a11yUtils.ts +7 -0
- package/src/components/DataTable/utils/debugTools.ts +18 -113
- package/src/components/DataTable/utils/errorHandling.ts +12 -0
- package/src/components/DataTable/utils/exportUtils.ts +9 -0
- package/src/components/DataTable/utils/flexibleImport.ts +12 -48
- package/src/components/DataTable/utils/paginationUtils.ts +8 -0
- package/src/components/DataTable/utils/performanceUtils.ts +5 -1
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
- package/src/components/ErrorBoundary/index.ts +27 -2
- package/src/components/EventSelector/EventSelector.tsx +3 -0
- package/src/components/FileDisplay/FileDisplay.tsx +32 -18
- package/src/components/FileUpload/FileUpload.tsx +22 -2
- package/src/components/Footer/Footer.test.tsx +16 -16
- package/src/components/Footer/Footer.tsx +14 -11
- package/src/components/Form/Form.tsx +1 -0
- package/src/components/Header/Header.tsx +21 -10
- package/src/components/Input/Input.test.tsx +2 -2
- package/src/components/Input/Input.tsx +8 -4
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
- package/src/components/LoginForm/LoginForm.tsx +4 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
- package/src/components/NavigationMenu/types.ts +56 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -2
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +32 -11
- package/src/components/PaceAppLayout/test-setup.tsx +1 -2
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
- package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
- package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
- package/src/components/Select/Select.tsx +80 -434
- package/src/components/Select/context.ts +23 -0
- package/src/components/Select/hooks/useSelectEvents.ts +87 -0
- package/src/components/Select/hooks/useSelectSearch.ts +91 -0
- package/src/components/Select/hooks/useSelectState.ts +104 -0
- package/src/components/Select/index.ts +9 -1
- package/src/components/Select/types.ts +123 -0
- package/src/components/Select/utils/text.ts +26 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
- package/src/components/Switch/Switch.tsx +4 -4
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.tsx +4 -0
- package/src/components/Tooltip/Tooltip.tsx +2 -2
- package/src/components/UserMenu/UserMenu.test.tsx +24 -11
- package/src/components/UserMenu/UserMenu.tsx +21 -18
- package/src/components/index.ts +2 -2
- package/src/hooks/__tests__/index.unit.test.ts +2 -5
- package/src/hooks/index.ts +1 -2
- package/src/hooks/public/usePublicEvent.ts +4 -0
- package/src/hooks/public/usePublicEventLogo.ts +4 -0
- package/src/hooks/public/usePublicFileDisplay.ts +4 -0
- package/src/hooks/public/usePublicRouteParams.ts +4 -0
- package/src/hooks/services/useAuth.ts +32 -0
- package/src/hooks/services/useCurrentEvent.ts +6 -0
- package/src/hooks/services/useCurrentOrganisation.ts +6 -0
- package/src/hooks/useDebounce.ts +9 -0
- package/src/hooks/useEventTheme.ts +6 -0
- package/src/hooks/useFileDisplay.ts +4 -0
- package/src/hooks/useFileReference.ts +25 -7
- package/src/hooks/useFileUrl.ts +11 -1
- package/src/hooks/useFocusManagement.ts +14 -0
- package/src/hooks/useFocusTrap.ts +3 -0
- package/src/hooks/useInactivityTracker.ts +3 -0
- package/src/hooks/useKeyboardShortcuts.ts +4 -0
- package/src/hooks/useOrganisationPermissions.ts +4 -0
- package/src/hooks/useOrganisationSecurity.ts +4 -0
- package/src/hooks/usePerformanceMonitor.ts +4 -0
- package/src/hooks/usePermissionCache.ts +7 -0
- package/src/hooks/useQueryCache.ts +12 -1
- package/src/hooks/useSessionRestoration.ts +4 -0
- package/src/hooks/useStorage.ts +4 -0
- package/src/hooks/useToast.ts +1 -1
- package/src/index.ts +2 -1
- package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
- package/src/providers/services/AuthServiceProvider.tsx +18 -0
- package/src/providers/services/EventServiceProvider.tsx +18 -0
- package/src/providers/services/InactivityServiceProvider.tsx +18 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +36 -0
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
- package/src/rbac/README.md +1 -1
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +2 -2
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
- package/src/rbac/adapters.tsx +14 -5
- package/src/rbac/api.ts +100 -67
- package/src/rbac/components/NavigationProvider.tsx +4 -1
- package/src/rbac/components/PagePermissionGuard.tsx +157 -17
- package/src/rbac/components/RoleBasedRouter.tsx +5 -1
- package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
- package/src/rbac/components/SecureDataProvider.tsx +20 -5
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
- package/src/rbac/engine.ts +38 -14
- package/src/rbac/hooks/permissions/index.ts +7 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
- package/src/rbac/hooks/permissions/useCan.ts +347 -0
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
- package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
- package/src/rbac/hooks/useCan.test.ts +71 -64
- package/src/rbac/hooks/usePermissions.ts +14 -995
- package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
- package/src/rbac/hooks/useResourcePermissions.ts +14 -4
- package/src/rbac/hooks/useSecureSupabase.ts +33 -13
- package/src/rbac/permissions.ts +0 -30
- package/src/rbac/secureClient.ts +200 -61
- package/src/rbac/types.ts +8 -0
- package/src/theming/__tests__/parseEventColours.test.ts +6 -9
- package/src/theming/parseEventColours.ts +5 -19
- package/src/types/vitest-globals.d.ts +51 -26
- package/src/utils/__mocks__/supabaseMock.ts +1 -3
- package/src/utils/__tests__/formatting.unit.test.ts +4 -4
- package/src/utils/__tests__/index.unit.test.ts +2 -2
- package/src/utils/audit/audit.ts +0 -3
- package/src/utils/core/cn.ts +1 -1
- package/src/utils/file-reference/index.ts +53 -1
- package/src/utils/formatting/formatting.ts +8 -18
- package/src/utils/index.ts +0 -1
- package/dist/chunk-3QRJFVBR.js.map +0 -1
- package/dist/chunk-3XTALGJF.js.map +0 -1
- package/dist/chunk-4N5C5XZU.js.map +0 -1
- package/dist/chunk-4ZC4GX36.js.map +0 -1
- package/dist/chunk-BYFSK72L.js.map +0 -1
- package/dist/chunk-EXUD6RNJ.js +0 -451
- package/dist/chunk-EXUD6RNJ.js.map +0 -1
- package/dist/chunk-GLK6VM3F.js.map +0 -1
- package/dist/chunk-I7PSE6JW.js.map +0 -1
- package/dist/chunk-JBKQ3SAO.js.map +0 -1
- package/dist/chunk-KNC55RTG.js.map +0 -1
- package/dist/chunk-LXQLPRQ2.js.map +0 -1
- package/dist/chunk-R77UEZ4E.js.map +0 -1
- package/dist/chunk-SQGMNID3.js.map +0 -1
- package/dist/chunk-T33XF5ZC.js.map +0 -1
- package/dist/chunk-XM25TVIE.js.map +0 -1
- package/docs/api/classes/ErrorBoundary.md +0 -144
- package/docs/migration/quick-migration-guide.md +0 -356
- package/docs/migration/service-architecture.md +0 -281
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
- package/src/hooks/useSecureDataAccess.test.ts +0 -559
- package/src/hooks/useSecureDataAccess.ts +0 -681
- /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-TPTKCX4D.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
- /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
- /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
- /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
- /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
- /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { UseSelectSearchProps } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for managing Select search functionality.
|
|
6
|
+
* Filters select items based on search term.
|
|
7
|
+
*
|
|
8
|
+
* @param props - Select search configuration
|
|
9
|
+
*/
|
|
10
|
+
export const useSelectSearch = ({
|
|
11
|
+
children,
|
|
12
|
+
searchable = false,
|
|
13
|
+
searchTerm: controlledSearchTerm,
|
|
14
|
+
onSearchChange,
|
|
15
|
+
}: UseSelectSearchProps) => {
|
|
16
|
+
const [internalSearchTerm, setInternalSearchTerm] = React.useState("");
|
|
17
|
+
const [filteredChildren, setFilteredChildren] =
|
|
18
|
+
React.useState<React.ReactNode>(children);
|
|
19
|
+
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
|
20
|
+
|
|
21
|
+
const searchTerm =
|
|
22
|
+
controlledSearchTerm !== undefined
|
|
23
|
+
? controlledSearchTerm
|
|
24
|
+
: internalSearchTerm;
|
|
25
|
+
|
|
26
|
+
const setSearchTerm = React.useCallback(
|
|
27
|
+
(term: string) => {
|
|
28
|
+
if (controlledSearchTerm === undefined) {
|
|
29
|
+
setInternalSearchTerm(term);
|
|
30
|
+
}
|
|
31
|
+
onSearchChange?.(term);
|
|
32
|
+
},
|
|
33
|
+
[controlledSearchTerm, onSearchChange]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
if (!searchable || !searchTerm) {
|
|
38
|
+
setFilteredChildren(children);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const filterChildren = (nodes: React.ReactNode): React.ReactNode => {
|
|
43
|
+
return React.Children.map(nodes, (child) => {
|
|
44
|
+
if (!React.isValidElement(child)) return child;
|
|
45
|
+
|
|
46
|
+
const childProps = child.props as {
|
|
47
|
+
"data-testid"?: string;
|
|
48
|
+
value?: unknown;
|
|
49
|
+
children?: React.ReactNode;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
};
|
|
52
|
+
const isSelectItem =
|
|
53
|
+
childProps &&
|
|
54
|
+
(childProps["data-testid"] === "select-item" ||
|
|
55
|
+
childProps.value !== undefined);
|
|
56
|
+
|
|
57
|
+
if (isSelectItem) {
|
|
58
|
+
const childText = React.Children.toArray(
|
|
59
|
+
childProps.children
|
|
60
|
+
).join(" ");
|
|
61
|
+
const searchLower = searchTerm.toLowerCase();
|
|
62
|
+
|
|
63
|
+
if (childText.toLowerCase().includes(searchLower)) {
|
|
64
|
+
return child;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (childProps.children) {
|
|
70
|
+
const filteredChildChildren = filterChildren(childProps.children);
|
|
71
|
+
if (React.Children.count(filteredChildChildren) > 0) {
|
|
72
|
+
return React.cloneElement(child, {}, filteredChildChildren);
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return child;
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const filtered = filterChildren(children);
|
|
82
|
+
setFilteredChildren(filtered);
|
|
83
|
+
}, [children, searchTerm, searchable]);
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
searchTerm,
|
|
87
|
+
setSearchTerm,
|
|
88
|
+
filteredChildren,
|
|
89
|
+
searchInputRef,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type {
|
|
3
|
+
SelectActions,
|
|
4
|
+
SelectState,
|
|
5
|
+
UseSelectStateProps,
|
|
6
|
+
} from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hook for managing Select component state.
|
|
10
|
+
* Handles controlled and uncontrolled value, open state, and disabled state.
|
|
11
|
+
*
|
|
12
|
+
* @param props - Select state configuration
|
|
13
|
+
* @returns Select state and actions
|
|
14
|
+
*/
|
|
15
|
+
export const useSelectState = ({
|
|
16
|
+
value: controlledValue,
|
|
17
|
+
defaultValue = "",
|
|
18
|
+
selectedText: controlledSelectedText,
|
|
19
|
+
open: controlledOpen,
|
|
20
|
+
defaultOpen = false,
|
|
21
|
+
disabled = false,
|
|
22
|
+
onValueChange,
|
|
23
|
+
onOpenChange,
|
|
24
|
+
}: UseSelectStateProps) => {
|
|
25
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
26
|
+
const [internalSelectedText, setInternalSelectedText] = React.useState("");
|
|
27
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
28
|
+
|
|
29
|
+
const value = controlledValue !== undefined ? controlledValue : internalValue;
|
|
30
|
+
const selectedText =
|
|
31
|
+
controlledSelectedText !== undefined
|
|
32
|
+
? controlledSelectedText
|
|
33
|
+
: internalSelectedText;
|
|
34
|
+
const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
|
|
35
|
+
|
|
36
|
+
const setValue = React.useCallback(
|
|
37
|
+
(newValue: string, newText: string) => {
|
|
38
|
+
if (controlledValue === undefined) {
|
|
39
|
+
setInternalValue(newValue);
|
|
40
|
+
setInternalSelectedText(newText);
|
|
41
|
+
}
|
|
42
|
+
onValueChange?.(newValue);
|
|
43
|
+
|
|
44
|
+
if (controlledOpen === undefined) {
|
|
45
|
+
setInternalOpen(false);
|
|
46
|
+
}
|
|
47
|
+
onOpenChange?.(false);
|
|
48
|
+
},
|
|
49
|
+
[controlledValue, onValueChange, controlledOpen, onOpenChange]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const setOpen = React.useCallback(
|
|
53
|
+
(newOpen: boolean) => {
|
|
54
|
+
if (disabled) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (newOpen) {
|
|
59
|
+
const allTriggers = document.querySelectorAll(
|
|
60
|
+
'[data-testid="select-trigger"]'
|
|
61
|
+
);
|
|
62
|
+
allTriggers.forEach((trigger) => {
|
|
63
|
+
if (trigger.getAttribute("aria-expanded") === "true") {
|
|
64
|
+
const selectRoot = trigger.closest('[data-testid="select-root"]');
|
|
65
|
+
if (selectRoot) {
|
|
66
|
+
const closeEvent = new CustomEvent("closeSelect");
|
|
67
|
+
selectRoot.dispatchEvent(closeEvent);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (controlledOpen === undefined) {
|
|
74
|
+
setInternalOpen(newOpen);
|
|
75
|
+
}
|
|
76
|
+
onOpenChange?.(newOpen);
|
|
77
|
+
},
|
|
78
|
+
[controlledOpen, onOpenChange, disabled]
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const setSelectedText = React.useCallback(
|
|
82
|
+
(newText: string) => {
|
|
83
|
+
if (controlledSelectedText === undefined) {
|
|
84
|
+
setInternalSelectedText(newText);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
[controlledSelectedText]
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const state: SelectState = {
|
|
91
|
+
value,
|
|
92
|
+
selectedText,
|
|
93
|
+
open,
|
|
94
|
+
disabled,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const actions: SelectActions = {
|
|
98
|
+
setValue,
|
|
99
|
+
setOpen,
|
|
100
|
+
setSelectedText,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return { state, actions };
|
|
104
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ButtonProps } from "../Button/Button";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Direction for Select dropdown opening.
|
|
6
|
+
* Controls whether the dropdown opens upward or downward.
|
|
7
|
+
*/
|
|
8
|
+
export type SelectDirection = "up" | "down";
|
|
9
|
+
|
|
10
|
+
export interface SelectState {
|
|
11
|
+
value: string;
|
|
12
|
+
selectedText: string;
|
|
13
|
+
open: boolean;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SelectActions {
|
|
18
|
+
setValue: (value: string, text: string) => void;
|
|
19
|
+
setOpen: (open: boolean) => void;
|
|
20
|
+
setSelectedText: (text: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SelectEventHandlers {
|
|
24
|
+
onValueChange?: (value: string) => void;
|
|
25
|
+
onOpenChange?: (open: boolean) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Props for the useSelectState hook.
|
|
30
|
+
*/
|
|
31
|
+
export interface UseSelectStateProps {
|
|
32
|
+
value?: string;
|
|
33
|
+
defaultValue?: string;
|
|
34
|
+
selectedText?: string;
|
|
35
|
+
open?: boolean;
|
|
36
|
+
defaultOpen?: boolean;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
onValueChange?: (value: string) => void;
|
|
39
|
+
onOpenChange?: (open: boolean) => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Props for the useSelectEvents hook.
|
|
44
|
+
*/
|
|
45
|
+
export interface UseSelectEventsProps {
|
|
46
|
+
state: SelectState;
|
|
47
|
+
actions: SelectActions;
|
|
48
|
+
selectRef: React.RefObject<HTMLElement | null>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Props for the useSelectSearch hook.
|
|
53
|
+
*/
|
|
54
|
+
export interface UseSelectSearchProps {
|
|
55
|
+
children: React.ReactNode;
|
|
56
|
+
searchable?: boolean;
|
|
57
|
+
searchTerm?: string;
|
|
58
|
+
onSearchChange?: (term: string) => void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Select context value interface.
|
|
63
|
+
* Provides state and actions to Select child components.
|
|
64
|
+
*/
|
|
65
|
+
export interface SelectContextValue extends SelectState {
|
|
66
|
+
actions: SelectActions;
|
|
67
|
+
registerItem?: (value: string, text: string) => void;
|
|
68
|
+
unregisterItem?: (value: string) => void;
|
|
69
|
+
direction?: SelectDirection;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Props for the Select root component.
|
|
74
|
+
*/
|
|
75
|
+
export interface SelectProps
|
|
76
|
+
extends Omit<
|
|
77
|
+
React.HTMLAttributes<HTMLFormElement>,
|
|
78
|
+
"onChange" | "onKeyDown" | "onFocus" | "onBlur"
|
|
79
|
+
> {
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
direction?: SelectDirection;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Props for the SelectTrigger component.
|
|
87
|
+
*/
|
|
88
|
+
export interface SelectTriggerProps
|
|
89
|
+
extends Omit<ButtonProps, "onClick" | "onKeyDown"> {
|
|
90
|
+
children: React.ReactNode;
|
|
91
|
+
asChild?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Props for the SelectValue component.
|
|
96
|
+
*/
|
|
97
|
+
export interface SelectValueProps {
|
|
98
|
+
placeholder?: string;
|
|
99
|
+
children?: React.ReactNode;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Props for the SelectContent component.
|
|
104
|
+
*/
|
|
105
|
+
export interface SelectContentProps {
|
|
106
|
+
children: React.ReactNode;
|
|
107
|
+
className?: string;
|
|
108
|
+
searchable?: boolean;
|
|
109
|
+
searchPlaceholder?: string;
|
|
110
|
+
maxHeight?: string;
|
|
111
|
+
style?: React.CSSProperties;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Props for the SelectItem component.
|
|
116
|
+
*/
|
|
117
|
+
export interface SelectItemProps {
|
|
118
|
+
value: string;
|
|
119
|
+
children: React.ReactNode;
|
|
120
|
+
disabled?: boolean;
|
|
121
|
+
className?: string;
|
|
122
|
+
onClick?: (e: React.MouseEvent) => void;
|
|
123
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extracts text content from React children.
|
|
5
|
+
* Recursively extracts all text content from a React node tree.
|
|
6
|
+
*
|
|
7
|
+
* @param children - React children to extract text from
|
|
8
|
+
* @returns Extracted text content as a string
|
|
9
|
+
*/
|
|
10
|
+
export const getTextContent = (children: React.ReactNode): string => {
|
|
11
|
+
if (typeof children === "string") return children;
|
|
12
|
+
if (typeof children === "number") return children.toString();
|
|
13
|
+
if (React.isValidElement(children)) {
|
|
14
|
+
const props = children.props as {
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
if (props.children) {
|
|
19
|
+
return getTextContent(props.children);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(children)) {
|
|
23
|
+
return children.map(getTextContent).join("");
|
|
24
|
+
}
|
|
25
|
+
return "";
|
|
26
|
+
};
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
import React from 'react';
|
|
39
39
|
import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';
|
|
40
|
+
import { Alert } from '../Alert';
|
|
40
41
|
import { cn } from '../../utils/core/cn';
|
|
41
42
|
|
|
42
43
|
export interface SessionRestorationLoaderProps {
|
|
@@ -51,7 +52,7 @@ export const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> =
|
|
|
51
52
|
className
|
|
52
53
|
}) => {
|
|
53
54
|
return (
|
|
54
|
-
<
|
|
55
|
+
<Alert
|
|
55
56
|
className={cn(
|
|
56
57
|
'flex flex-col items-center justify-center h-screen w-full gap-4 text-center p-4 bg-background',
|
|
57
58
|
className
|
|
@@ -61,10 +62,8 @@ export const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> =
|
|
|
61
62
|
aria-label={message}
|
|
62
63
|
>
|
|
63
64
|
<LoadingSpinner size="lg" />
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
65
|
+
<span className="text-sm text-sec-600">{message}</span>
|
|
66
|
+
</Alert>
|
|
68
67
|
);
|
|
69
68
|
};
|
|
70
69
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* const [checked, setChecked] = React.useState(false);
|
|
25
25
|
*
|
|
26
26
|
* return (
|
|
27
|
-
*
|
|
27
|
+
* <>
|
|
28
28
|
* <Switch
|
|
29
29
|
* checked={checked}
|
|
30
30
|
* onCheckedChange={setChecked}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* <label htmlFor="notifications">
|
|
34
34
|
* Enable notifications
|
|
35
35
|
* </label>
|
|
36
|
-
*
|
|
36
|
+
* </>
|
|
37
37
|
* );
|
|
38
38
|
* }
|
|
39
39
|
* ```
|
|
@@ -44,12 +44,12 @@
|
|
|
44
44
|
*
|
|
45
45
|
* function FormExample() {
|
|
46
46
|
* return (
|
|
47
|
-
*
|
|
47
|
+
* <>
|
|
48
48
|
* <Switch id="terms" />
|
|
49
49
|
* <Label htmlFor="terms">
|
|
50
50
|
* I agree to the terms and conditions
|
|
51
51
|
* </Label>
|
|
52
|
-
*
|
|
52
|
+
* </>
|
|
53
53
|
* );
|
|
54
54
|
* }
|
|
55
55
|
* ```
|
|
@@ -199,7 +199,7 @@ export interface TabsContentProps extends React.ComponentPropsWithoutRef<typeof
|
|
|
199
199
|
* @example
|
|
200
200
|
* ```tsx
|
|
201
201
|
* <TabsContent value="tab1">
|
|
202
|
-
* <
|
|
202
|
+
* <section>Content for tab 1</section>
|
|
203
203
|
* </TabsContent>
|
|
204
204
|
* ```
|
|
205
205
|
*/
|
|
@@ -267,6 +267,10 @@ ToastDescription.displayName = ToastPrimitives.Description.displayName
|
|
|
267
267
|
|
|
268
268
|
export interface ToastProps extends React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> {}
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Type for toast action elements.
|
|
272
|
+
* Represents a React element that can be used as a toast action button.
|
|
273
|
+
*/
|
|
270
274
|
export interface ToastActionElement extends React.ReactElement<typeof ToastAction> {}
|
|
271
275
|
|
|
272
276
|
/**
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
* <Button>Advanced Tooltip</Button>
|
|
37
37
|
* </TooltipTrigger>
|
|
38
38
|
* <TooltipContent side="top" className="bg-main-500 text-main-50">
|
|
39
|
-
* <
|
|
39
|
+
* <section className="space-y-1">
|
|
40
40
|
* <p className="font-semibold">Advanced Tooltip</p>
|
|
41
41
|
* <p className="text-xs">With custom styling</p>
|
|
42
|
-
* </
|
|
42
|
+
* </section>
|
|
43
43
|
* </TooltipContent>
|
|
44
44
|
* </TooltipRoot>
|
|
45
45
|
* </TooltipProvider>
|
|
@@ -563,7 +563,9 @@ describe('UserMenuLoading Component', () => {
|
|
|
563
563
|
it('renders loading state', () => {
|
|
564
564
|
renderWithProviders(<UserMenuLoading />);
|
|
565
565
|
|
|
566
|
-
|
|
566
|
+
// There are multiple "Loading..." texts (one visible, one sr-only), so use getAllByText
|
|
567
|
+
const loadingTexts = screen.getAllByText('Loading...');
|
|
568
|
+
expect(loadingTexts.length).toBeGreaterThan(0);
|
|
567
569
|
expect(screen.getByRole('button')).toBeDisabled();
|
|
568
570
|
});
|
|
569
571
|
|
|
@@ -572,31 +574,39 @@ describe('UserMenuLoading Component', () => {
|
|
|
572
574
|
|
|
573
575
|
const button = screen.getByRole('button');
|
|
574
576
|
expect(button).toHaveClass('flex', 'items-center', 'space-x-2');
|
|
575
|
-
|
|
576
|
-
// Check for animate-pulse on the inner div
|
|
577
|
-
const animatedDiv = button.querySelector('.animate-pulse');
|
|
578
|
-
expect(animatedDiv).toBeInTheDocument();
|
|
579
577
|
});
|
|
580
578
|
|
|
581
579
|
it('renders loading avatar placeholder', () => {
|
|
582
580
|
renderWithProviders(<UserMenuLoading />);
|
|
583
581
|
|
|
584
|
-
|
|
585
|
-
|
|
582
|
+
// UserMenuLoading doesn't have an avatar placeholder, just a spinner
|
|
583
|
+
const button = screen.getByRole('button');
|
|
584
|
+
expect(button).toBeInTheDocument();
|
|
585
|
+
// Check that LoadingSpinner is present (it has role="status")
|
|
586
|
+
const statusElements = screen.getAllByRole('status');
|
|
587
|
+
expect(statusElements.length).toBeGreaterThan(0);
|
|
586
588
|
});
|
|
587
589
|
|
|
588
590
|
it('renders with proper accessibility attributes', () => {
|
|
589
591
|
renderWithProviders(<UserMenuLoading />);
|
|
590
592
|
|
|
591
|
-
|
|
593
|
+
// LoadingSpinner has role="status"
|
|
594
|
+
const statusElements = screen.getAllByRole('status');
|
|
595
|
+
expect(statusElements.length).toBeGreaterThan(0);
|
|
596
|
+
// Button has aria-label
|
|
592
597
|
expect(screen.getByLabelText('Loading user menu')).toBeInTheDocument();
|
|
593
598
|
});
|
|
594
599
|
|
|
595
600
|
it('renders with aria-live polite', () => {
|
|
596
601
|
renderWithProviders(<UserMenuLoading />);
|
|
597
602
|
|
|
598
|
-
|
|
599
|
-
|
|
603
|
+
// LoadingSpinner has role="status" but may not have aria-live
|
|
604
|
+
// The button has aria-label for screen readers
|
|
605
|
+
const statusElements = screen.getAllByRole('status');
|
|
606
|
+
expect(statusElements.length).toBeGreaterThan(0);
|
|
607
|
+
// Check that button is accessible
|
|
608
|
+
const button = screen.getByLabelText('Loading user menu');
|
|
609
|
+
expect(button).toBeInTheDocument();
|
|
600
610
|
});
|
|
601
611
|
});
|
|
602
612
|
|
|
@@ -611,7 +621,10 @@ describe('UserMenuLoading Component', () => {
|
|
|
611
621
|
it('provides loading status to screen readers', () => {
|
|
612
622
|
renderWithProviders(<UserMenuLoading />);
|
|
613
623
|
|
|
614
|
-
|
|
624
|
+
// Button has aria-label for screen readers
|
|
625
|
+
const button = screen.getByLabelText('Loading user menu');
|
|
626
|
+
expect(button).toBeInTheDocument();
|
|
627
|
+
expect(button).toBeDisabled();
|
|
615
628
|
});
|
|
616
629
|
});
|
|
617
630
|
});
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
*
|
|
61
61
|
* // User menu in header
|
|
62
62
|
* <Header>
|
|
63
|
-
* <
|
|
63
|
+
* <nav className="flex items-center gap-4">
|
|
64
64
|
* <Navigation />
|
|
65
65
|
* <UserMenu
|
|
66
66
|
* user={user}
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
* onChangePassword={handlePasswordChange}
|
|
69
69
|
* className="ml-auto"
|
|
70
70
|
* />
|
|
71
|
-
* </
|
|
71
|
+
* </nav>
|
|
72
72
|
* </Header>
|
|
73
73
|
* ```
|
|
74
74
|
*
|
|
@@ -124,7 +124,11 @@ import {
|
|
|
124
124
|
import { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';
|
|
125
125
|
import { Avatar } from '../Avatar';
|
|
126
126
|
import { Button } from '../Button';
|
|
127
|
+
import { LoadingSpinner } from '../LoadingSpinner';
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Props for the UserMenu component.
|
|
131
|
+
*/
|
|
128
132
|
export interface UserMenuProps {
|
|
129
133
|
user: User | null;
|
|
130
134
|
onSignOut?: () => Promise<void>;
|
|
@@ -179,10 +183,10 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
|
|
|
179
183
|
</SelectTrigger>
|
|
180
184
|
<SelectContent>
|
|
181
185
|
<SelectLabel className="font-normal">
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
<
|
|
185
|
-
</
|
|
186
|
+
<li className="pt-2">
|
|
187
|
+
{userInfo.displayName}<br/>
|
|
188
|
+
<span className="text-muted-foreground">{userInfo.email}</span>
|
|
189
|
+
</li>
|
|
186
190
|
</SelectLabel>
|
|
187
191
|
<SelectSeparator />
|
|
188
192
|
<DialogTrigger asChild>
|
|
@@ -222,18 +226,17 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
|
|
|
222
226
|
|
|
223
227
|
export const UserMenuLoading = React.memo(function UserMenuLoading() {
|
|
224
228
|
return (
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
</div>
|
|
229
|
+
<Button
|
|
230
|
+
type="button"
|
|
231
|
+
disabled
|
|
232
|
+
variant="outline"
|
|
233
|
+
className="flex items-center space-x-2"
|
|
234
|
+
aria-label="Loading user menu"
|
|
235
|
+
>
|
|
236
|
+
<LoadingSpinner size="sm" className="inline-block mr-2" />
|
|
237
|
+
<span className="truncate max-w-[150px]">Loading...</span>
|
|
238
|
+
<ChevronDown className="w-4 h-4 text-muted-foreground" />
|
|
239
|
+
</Button>
|
|
237
240
|
);
|
|
238
241
|
});
|
|
239
242
|
|
package/src/components/index.ts
CHANGED
|
@@ -228,8 +228,8 @@ export * from './PaceLoginPage';
|
|
|
228
228
|
// UTILITY COMPONENTS
|
|
229
229
|
// ============================================================================
|
|
230
230
|
|
|
231
|
-
export { ErrorBoundary } from './ErrorBoundary';
|
|
232
|
-
export type { ErrorBoundaryProps, ErrorBoundaryState } from './ErrorBoundary';
|
|
231
|
+
export { ErrorBoundary, ErrorBoundaryProvider } from './ErrorBoundary';
|
|
232
|
+
export type { ErrorBoundaryProps, ErrorBoundaryState, ErrorBoundaryProviderProps, GlobalErrorHandler } from './ErrorBoundary';
|
|
233
233
|
export { LoadingSpinner } from './LoadingSpinner';
|
|
234
234
|
export { SessionRestorationLoader } from './SessionRestorationLoader';
|
|
235
235
|
export type { SessionRestorationLoaderProps } from './SessionRestorationLoader';
|
|
@@ -64,10 +64,7 @@ describe('hooks index exports', () => {
|
|
|
64
64
|
expect(typeof Hooks.useOrganisationPermissions).toBe('function');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
expect(Hooks).toHaveProperty('useSecureDataAccess');
|
|
69
|
-
expect(typeof Hooks.useSecureDataAccess).toBe('function');
|
|
70
|
-
});
|
|
67
|
+
// useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
71
68
|
|
|
72
69
|
it('should export useOrganisationSecurity', () => {
|
|
73
70
|
expect(Hooks).toHaveProperty('useOrganisationSecurity');
|
|
@@ -190,7 +187,7 @@ describe('hooks index exports', () => {
|
|
|
190
187
|
'useDebounce',
|
|
191
188
|
'useDataTableState',
|
|
192
189
|
'useOrganisationPermissions',
|
|
193
|
-
'useSecureDataAccess',
|
|
190
|
+
// 'useSecureDataAccess', // Removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
194
191
|
'useOrganisationSecurity',
|
|
195
192
|
'useZodForm',
|
|
196
193
|
'useComponentPerformance',
|
package/src/hooks/index.ts
CHANGED
|
@@ -33,9 +33,8 @@ export type { UseAddressAutocompleteOptions, UseAddressAutocompleteReturn } from
|
|
|
33
33
|
|
|
34
34
|
// === ORGANISATION HOOKS ===
|
|
35
35
|
export { useOrganisationPermissions } from './useOrganisationPermissions';
|
|
36
|
-
|
|
36
|
+
// useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
|
|
37
37
|
export type { UseOrganisationPermissionsReturn } from './useOrganisationPermissions';
|
|
38
|
-
export type { SecureDataAccessReturn } from './useSecureDataAccess';
|
|
39
38
|
export { useOrganisationSecurity } from './useOrganisationSecurity';
|
|
40
39
|
export type { OrganisationSecurityHook } from './useOrganisationSecurity';
|
|
41
40
|
|
|
@@ -70,6 +70,10 @@ import { logger } from '../../utils/core/logger';
|
|
|
70
70
|
// Simple in-memory cache for public data
|
|
71
71
|
const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Return value of the usePublicEvent hook.
|
|
75
|
+
* Provides event data, loading state, error, and refetch function.
|
|
76
|
+
*/
|
|
73
77
|
export interface UsePublicEventReturn {
|
|
74
78
|
/** The event data, null if not loaded or not found */
|
|
75
79
|
event: Event | null;
|
|
@@ -74,6 +74,10 @@ const log = createLogger('usePublicEventLogo');
|
|
|
74
74
|
// Simple in-memory cache for public data
|
|
75
75
|
const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Return value of the usePublicEventLogo hook.
|
|
79
|
+
* Provides logo URL, fallback text, loading state, error, and refetch function.
|
|
80
|
+
*/
|
|
77
81
|
export interface UsePublicEventLogoReturn {
|
|
78
82
|
/** The logo URL if available, null if not found or error */
|
|
79
83
|
logoUrl: string | null;
|