@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.
Files changed (502) hide show
  1. package/CHANGELOG.md +43 -10
  2. package/cursor-rules/00-pace-core-compliance.mdc +18 -91
  3. package/cursor-rules/01-standards-compliance.mdc +16 -47
  4. package/cursor-rules/02-project-structure.mdc +4 -4
  5. package/cursor-rules/03-solid-principles.mdc +45 -164
  6. package/cursor-rules/04-testing-standards.mdc +22 -69
  7. package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
  8. package/cursor-rules/06-code-quality.mdc +42 -125
  9. package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
  10. package/cursor-rules/08-markup-quality.mdc +452 -0
  11. package/cursor-rules/CHANGELOG.md +18 -0
  12. package/cursor-rules/README.md +2 -1
  13. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  14. package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
  15. package/dist/{DataTable-DQ7RSOHE.js → DataTable-TPTKCX4D.js} +10 -9
  16. package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +356 -111
  17. package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  18. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  19. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  20. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  21. package/dist/chunk-24UVZUZG.js.map +1 -0
  22. package/dist/{chunk-4N5C5XZU.js → chunk-2UOI2FG5.js} +4 -4
  23. package/dist/chunk-2UOI2FG5.js.map +1 -0
  24. package/dist/{chunk-T33XF5ZC.js → chunk-3XC4CPTD.js} +4317 -3963
  25. package/dist/chunk-3XC4CPTD.js.map +1 -0
  26. package/dist/{chunk-4ZC4GX36.js → chunk-6J4GEEJR.js} +172 -45
  27. package/dist/chunk-6J4GEEJR.js.map +1 -0
  28. package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
  29. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  30. package/dist/{chunk-BYFSK72L.js → chunk-EHMR7VYL.js} +4 -4
  31. package/dist/chunk-EHMR7VYL.js.map +1 -0
  32. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  33. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  34. package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
  35. package/dist/chunk-FFQEQTNW.js.map +1 -0
  36. package/dist/chunk-FMUCXFII.js +76 -0
  37. package/dist/chunk-FMUCXFII.js.map +1 -0
  38. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  39. package/dist/chunk-L4OXEN46.js.map +1 -0
  40. package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
  41. package/dist/chunk-M43Y4SSO.js.map +1 -0
  42. package/dist/{chunk-3XTALGJF.js → chunk-MMZ7JXPU.js} +60 -223
  43. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  44. package/dist/{chunk-GLK6VM3F.js → chunk-NECFR5MM.js} +254 -170
  45. package/dist/chunk-NECFR5MM.js.map +1 -0
  46. package/dist/{chunk-JBKQ3SAO.js → chunk-SFZUDBL5.js} +40 -4
  47. package/dist/chunk-SFZUDBL5.js.map +1 -0
  48. package/dist/{chunk-XM25TVIE.js → chunk-XWQCNGTQ.js} +724 -363
  49. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  50. package/dist/components.d.ts +5 -5
  51. package/dist/components.js +14 -11
  52. package/dist/components.js.map +1 -1
  53. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  54. package/dist/hooks.d.ts +55 -122
  55. package/dist/hooks.js +8 -12
  56. package/dist/hooks.js.map +1 -1
  57. package/dist/index.d.ts +60 -13
  58. package/dist/index.js +19 -19
  59. package/dist/index.js.map +1 -1
  60. package/dist/providers.d.ts +21 -3
  61. package/dist/providers.js +2 -2
  62. package/dist/rbac/index.d.ts +145 -114
  63. package/dist/rbac/index.js +8 -11
  64. package/dist/theming/runtime.d.ts +1 -13
  65. package/dist/theming/runtime.js +1 -1
  66. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  67. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  68. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  69. package/dist/types.d.ts +2 -2
  70. package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +31 -1
  71. package/dist/utils.d.ts +4 -5
  72. package/dist/utils.js +14 -14
  73. package/dist/utils.js.map +1 -1
  74. package/docs/api/README.md +7 -1
  75. package/docs/api/classes/ColumnFactory.md +8 -8
  76. package/docs/api/classes/InvalidScopeError.md +4 -4
  77. package/docs/api/classes/Logger.md +1 -1
  78. package/docs/api/classes/MissingUserContextError.md +4 -4
  79. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  80. package/docs/api/classes/PermissionDeniedError.md +4 -4
  81. package/docs/api/classes/RBACAuditManager.md +1 -1
  82. package/docs/api/classes/RBACCache.md +1 -1
  83. package/docs/api/classes/RBACEngine.md +1 -1
  84. package/docs/api/classes/RBACError.md +4 -4
  85. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  86. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  87. package/docs/api/classes/StorageUtils.md +1 -1
  88. package/docs/api/enums/FileCategory.md +1 -1
  89. package/docs/api/enums/LogLevel.md +1 -1
  90. package/docs/api/enums/RBACErrorCode.md +1 -1
  91. package/docs/api/enums/RPCFunction.md +1 -1
  92. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  93. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  94. package/docs/api/interfaces/AggregateConfig.md +4 -4
  95. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  96. package/docs/api/interfaces/AvatarProps.md +1 -1
  97. package/docs/api/interfaces/BadgeProps.md +9 -2
  98. package/docs/api/interfaces/ButtonProps.md +7 -4
  99. package/docs/api/interfaces/CalendarProps.md +8 -5
  100. package/docs/api/interfaces/CardProps.md +8 -5
  101. package/docs/api/interfaces/ColorPalette.md +1 -1
  102. package/docs/api/interfaces/ColorShade.md +1 -1
  103. package/docs/api/interfaces/ComplianceResult.md +1 -1
  104. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  105. package/docs/api/interfaces/DataRecord.md +1 -1
  106. package/docs/api/interfaces/DataTableAction.md +24 -21
  107. package/docs/api/interfaces/DataTableColumn.md +31 -31
  108. package/docs/api/interfaces/DataTableProps.md +1 -1
  109. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  110. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  111. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  112. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  113. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  114. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  115. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  116. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  117. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  118. package/docs/api/interfaces/ExportColumn.md +1 -1
  119. package/docs/api/interfaces/ExportOptions.md +8 -8
  120. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  121. package/docs/api/interfaces/FileMetadata.md +1 -1
  122. package/docs/api/interfaces/FileReference.md +1 -1
  123. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  124. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  125. package/docs/api/interfaces/FileUploadProps.md +26 -23
  126. package/docs/api/interfaces/FooterProps.md +10 -8
  127. package/docs/api/interfaces/FormFieldProps.md +10 -10
  128. package/docs/api/interfaces/FormProps.md +1 -1
  129. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  130. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  131. package/docs/api/interfaces/InputProps.md +7 -4
  132. package/docs/api/interfaces/LabelProps.md +1 -1
  133. package/docs/api/interfaces/LoggerConfig.md +1 -1
  134. package/docs/api/interfaces/LoginFormProps.md +14 -11
  135. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  136. package/docs/api/interfaces/NavigationContextType.md +1 -1
  137. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  138. package/docs/api/interfaces/NavigationItem.md +11 -11
  139. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  140. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  141. package/docs/api/interfaces/Organisation.md +1 -1
  142. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  143. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  144. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  145. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  146. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  147. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  148. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  149. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  150. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  151. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  152. package/docs/api/interfaces/PaletteData.md +1 -1
  153. package/docs/api/interfaces/ParsedAddress.md +1 -1
  154. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  155. package/docs/api/interfaces/ProgressProps.md +1 -1
  156. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  157. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  158. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  159. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  160. package/docs/api/interfaces/QuickFix.md +1 -1
  161. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  162. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  163. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  164. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  165. package/docs/api/interfaces/RBACConfig.md +1 -1
  166. package/docs/api/interfaces/RBACContext.md +1 -1
  167. package/docs/api/interfaces/RBACLogger.md +1 -1
  168. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  169. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  170. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  171. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  172. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  173. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  174. package/docs/api/interfaces/RBACResult.md +1 -1
  175. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  176. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  177. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  178. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  181. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  182. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  183. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  184. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  185. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  186. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  187. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  188. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  189. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  190. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  191. package/docs/api/interfaces/RouteConfig.md +1 -1
  192. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  193. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  194. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  195. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  196. package/docs/api/interfaces/SetupIssue.md +1 -1
  197. package/docs/api/interfaces/StorageConfig.md +1 -1
  198. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  199. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  200. package/docs/api/interfaces/StorageListOptions.md +1 -1
  201. package/docs/api/interfaces/StorageListResult.md +1 -1
  202. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  203. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  204. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  205. package/docs/api/interfaces/StyleImport.md +1 -1
  206. package/docs/api/interfaces/SwitchProps.md +1 -1
  207. package/docs/api/interfaces/TabsContentProps.md +1 -1
  208. package/docs/api/interfaces/TabsListProps.md +1 -1
  209. package/docs/api/interfaces/TabsProps.md +1 -1
  210. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  211. package/docs/api/interfaces/TextareaProps.md +1 -1
  212. package/docs/api/interfaces/ToastActionElement.md +4 -1
  213. package/docs/api/interfaces/ToastProps.md +1 -1
  214. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  215. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  216. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  217. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  218. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  219. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  220. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  221. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  222. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  223. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  224. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  225. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  226. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  227. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  228. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  229. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  230. package/docs/api/interfaces/UserEventAccess.md +14 -11
  231. package/docs/api/interfaces/UserMenuProps.md +8 -6
  232. package/docs/api/interfaces/UserProfile.md +1 -1
  233. package/docs/api/modules.md +575 -634
  234. package/docs/architecture/database-schema-requirements.md +161 -0
  235. package/docs/core-concepts/rbac-system.md +3 -3
  236. package/docs/documentation-index.md +2 -4
  237. package/docs/getting-started/cursor-rules.md +2 -1
  238. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  239. package/docs/migration/MIGRATION_GUIDE.md +2 -24
  240. package/docs/migration/README.md +52 -6
  241. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  242. package/docs/migration/database-changes-december-2025.md +3 -3
  243. package/docs/rbac/event-based-apps.md +1 -1
  244. package/docs/rbac/getting-started.md +1 -1
  245. package/docs/rbac/quick-start.md +1 -1
  246. package/docs/standards/README.md +1 -0
  247. package/package.json +2 -1
  248. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  249. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  250. package/scripts/audit/core/checks/bundle.cjs +142 -0
  251. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +714 -687
  252. package/scripts/audit/core/checks/config.cjs +54 -0
  253. package/scripts/audit/core/checks/coverage.cjs +84 -0
  254. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  255. package/scripts/audit/core/checks/documentation.cjs +203 -0
  256. package/scripts/audit/core/checks/environment.cjs +128 -0
  257. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  258. package/scripts/audit/core/checks/forms.cjs +172 -0
  259. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  260. package/scripts/audit/core/checks/hooks.cjs +334 -0
  261. package/scripts/audit/core/checks/imports.cjs +244 -0
  262. package/scripts/audit/core/checks/performance.cjs +325 -0
  263. package/scripts/audit/core/checks/routes.cjs +117 -0
  264. package/scripts/audit/core/checks/state.cjs +130 -0
  265. package/scripts/audit/core/checks/structure.cjs +65 -0
  266. package/scripts/audit/core/checks/style.cjs +584 -0
  267. package/scripts/audit/core/checks/testing.cjs +122 -0
  268. package/scripts/audit/core/checks/typescript.cjs +61 -0
  269. package/scripts/audit/core/scanner.cjs +199 -0
  270. package/scripts/audit/core/utils.cjs +137 -0
  271. package/scripts/audit/index.cjs +223 -0
  272. package/scripts/audit/reporters/console.cjs +151 -0
  273. package/scripts/audit/reporters/json.cjs +54 -0
  274. package/scripts/audit/reporters/markdown.cjs +124 -0
  275. package/scripts/audit-consuming-app.cjs +61 -936
  276. package/scripts/build-docs/build-decision.js +240 -0
  277. package/scripts/build-docs/cache-utils.js +105 -0
  278. package/scripts/build-docs/content-normalization.js +150 -0
  279. package/scripts/build-docs/file-utils.js +105 -0
  280. package/scripts/build-docs/git-utils.js +86 -0
  281. package/scripts/build-docs/hash-utils.js +116 -0
  282. package/scripts/build-docs/typedoc-runner.js +220 -0
  283. package/scripts/build-docs-incremental.js +77 -913
  284. package/scripts/utils/command-runner.js +16 -11
  285. package/scripts/validate-formats.js +61 -56
  286. package/scripts/validate-master.js +74 -69
  287. package/scripts/validate-pre-publish.js +70 -65
  288. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  289. package/src/components/Alert/Alert.test.tsx +12 -18
  290. package/src/components/Alert/Alert.tsx +5 -7
  291. package/src/components/Avatar/Avatar.test.tsx +4 -4
  292. package/src/components/Badge/Badge.tsx +14 -0
  293. package/src/components/Button/Button.tsx +22 -0
  294. package/src/components/Calendar/Calendar.tsx +8 -2
  295. package/src/components/Card/Card.tsx +4 -0
  296. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  297. package/src/components/Checkbox/Checkbox.tsx +2 -2
  298. package/src/components/DataTable/DataTable.tsx +38 -4
  299. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  300. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
  301. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  302. package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
  303. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  304. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  305. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  306. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  307. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  308. package/src/components/DataTable/components/DataTableCore.tsx +196 -554
  309. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  310. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  311. package/src/components/DataTable/components/DataTableModals.tsx +8 -0
  312. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  313. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  314. package/src/components/DataTable/components/EditFields.tsx +307 -0
  315. package/src/components/DataTable/components/EditableRow.tsx +8 -0
  316. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  317. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  318. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  319. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  320. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  321. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  322. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  323. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  324. package/src/components/DataTable/components/UnifiedTableBody.tsx +61 -849
  325. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  326. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  327. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  328. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  329. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  330. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  331. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  332. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  333. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  334. package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
  335. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  336. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  337. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  338. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  339. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  340. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  341. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  342. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  343. package/src/components/DataTable/styles.ts +6 -6
  344. package/src/components/DataTable/types.ts +6 -10
  345. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  346. package/src/components/DataTable/utils/debugTools.ts +18 -113
  347. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  348. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  349. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  350. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  351. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  352. package/src/components/Dialog/Dialog.tsx +2 -2
  353. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  354. package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
  355. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  356. package/src/components/ErrorBoundary/index.ts +27 -2
  357. package/src/components/EventSelector/EventSelector.tsx +3 -0
  358. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  359. package/src/components/FileUpload/FileUpload.tsx +22 -2
  360. package/src/components/Footer/Footer.test.tsx +16 -16
  361. package/src/components/Footer/Footer.tsx +14 -11
  362. package/src/components/Form/Form.tsx +1 -0
  363. package/src/components/Header/Header.tsx +21 -10
  364. package/src/components/Input/Input.test.tsx +2 -2
  365. package/src/components/Input/Input.tsx +8 -4
  366. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  367. package/src/components/LoginForm/LoginForm.tsx +4 -0
  368. package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
  369. package/src/components/NavigationMenu/types.ts +56 -0
  370. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  371. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  372. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -2
  373. package/src/components/PaceAppLayout/PaceAppLayout.tsx +32 -11
  374. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  375. package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
  376. package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
  377. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  378. package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
  379. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  380. package/src/components/Select/Select.tsx +80 -434
  381. package/src/components/Select/context.ts +23 -0
  382. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  383. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  384. package/src/components/Select/hooks/useSelectState.ts +104 -0
  385. package/src/components/Select/index.ts +9 -1
  386. package/src/components/Select/types.ts +123 -0
  387. package/src/components/Select/utils/text.ts +26 -0
  388. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
  389. package/src/components/Switch/Switch.tsx +4 -4
  390. package/src/components/Tabs/Tabs.tsx +1 -1
  391. package/src/components/Toast/Toast.tsx +4 -0
  392. package/src/components/Tooltip/Tooltip.tsx +2 -2
  393. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  394. package/src/components/UserMenu/UserMenu.tsx +21 -18
  395. package/src/components/index.ts +2 -2
  396. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  397. package/src/hooks/index.ts +1 -2
  398. package/src/hooks/public/usePublicEvent.ts +4 -0
  399. package/src/hooks/public/usePublicEventLogo.ts +4 -0
  400. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  401. package/src/hooks/public/usePublicRouteParams.ts +4 -0
  402. package/src/hooks/services/useAuth.ts +32 -0
  403. package/src/hooks/services/useCurrentEvent.ts +6 -0
  404. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  405. package/src/hooks/useDebounce.ts +9 -0
  406. package/src/hooks/useEventTheme.ts +6 -0
  407. package/src/hooks/useFileDisplay.ts +4 -0
  408. package/src/hooks/useFileReference.ts +25 -7
  409. package/src/hooks/useFileUrl.ts +11 -1
  410. package/src/hooks/useFocusManagement.ts +14 -0
  411. package/src/hooks/useFocusTrap.ts +3 -0
  412. package/src/hooks/useInactivityTracker.ts +3 -0
  413. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  414. package/src/hooks/useOrganisationPermissions.ts +4 -0
  415. package/src/hooks/useOrganisationSecurity.ts +4 -0
  416. package/src/hooks/usePerformanceMonitor.ts +4 -0
  417. package/src/hooks/usePermissionCache.ts +7 -0
  418. package/src/hooks/useQueryCache.ts +12 -1
  419. package/src/hooks/useSessionRestoration.ts +4 -0
  420. package/src/hooks/useStorage.ts +4 -0
  421. package/src/hooks/useToast.ts +1 -1
  422. package/src/index.ts +2 -1
  423. package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
  424. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  425. package/src/providers/services/EventServiceProvider.tsx +18 -0
  426. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  427. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  428. package/src/providers/services/UnifiedAuthProvider.tsx +36 -0
  429. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
  430. package/src/rbac/README.md +1 -1
  431. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +2 -2
  432. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  433. package/src/rbac/adapters.tsx +14 -5
  434. package/src/rbac/api.ts +100 -67
  435. package/src/rbac/components/NavigationProvider.tsx +4 -1
  436. package/src/rbac/components/PagePermissionGuard.tsx +157 -17
  437. package/src/rbac/components/RoleBasedRouter.tsx +5 -1
  438. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  439. package/src/rbac/components/SecureDataProvider.tsx +20 -5
  440. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  441. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  442. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  443. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  444. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  445. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  446. package/src/rbac/engine.ts +38 -14
  447. package/src/rbac/hooks/permissions/index.ts +7 -0
  448. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  449. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  450. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  451. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  452. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  453. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  454. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  455. package/src/rbac/hooks/useCan.test.ts +71 -64
  456. package/src/rbac/hooks/usePermissions.ts +14 -995
  457. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  458. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  459. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  460. package/src/rbac/permissions.ts +0 -30
  461. package/src/rbac/secureClient.ts +200 -61
  462. package/src/rbac/types.ts +8 -0
  463. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  464. package/src/theming/parseEventColours.ts +5 -19
  465. package/src/types/vitest-globals.d.ts +51 -26
  466. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  467. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  468. package/src/utils/__tests__/index.unit.test.ts +2 -2
  469. package/src/utils/audit/audit.ts +0 -3
  470. package/src/utils/core/cn.ts +1 -1
  471. package/src/utils/file-reference/index.ts +53 -1
  472. package/src/utils/formatting/formatting.ts +8 -18
  473. package/src/utils/index.ts +0 -1
  474. package/dist/chunk-3QRJFVBR.js.map +0 -1
  475. package/dist/chunk-3XTALGJF.js.map +0 -1
  476. package/dist/chunk-4N5C5XZU.js.map +0 -1
  477. package/dist/chunk-4ZC4GX36.js.map +0 -1
  478. package/dist/chunk-BYFSK72L.js.map +0 -1
  479. package/dist/chunk-EXUD6RNJ.js +0 -451
  480. package/dist/chunk-EXUD6RNJ.js.map +0 -1
  481. package/dist/chunk-GLK6VM3F.js.map +0 -1
  482. package/dist/chunk-I7PSE6JW.js.map +0 -1
  483. package/dist/chunk-JBKQ3SAO.js.map +0 -1
  484. package/dist/chunk-KNC55RTG.js.map +0 -1
  485. package/dist/chunk-LXQLPRQ2.js.map +0 -1
  486. package/dist/chunk-R77UEZ4E.js.map +0 -1
  487. package/dist/chunk-SQGMNID3.js.map +0 -1
  488. package/dist/chunk-T33XF5ZC.js.map +0 -1
  489. package/dist/chunk-XM25TVIE.js.map +0 -1
  490. package/docs/api/classes/ErrorBoundary.md +0 -144
  491. package/docs/migration/quick-migration-guide.md +0 -356
  492. package/docs/migration/service-architecture.md +0 -281
  493. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  494. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  495. package/src/hooks/useSecureDataAccess.ts +0 -681
  496. /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  497. /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  498. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  499. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  500. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  501. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  502. /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
+ };
@@ -1 +1,9 @@
1
- export * from './Select';
1
+ export * from './Select';
2
+ export type {
3
+ SelectContentProps,
4
+ SelectContextValue,
5
+ SelectItemProps,
6
+ SelectProps,
7
+ SelectTriggerProps,
8
+ SelectValueProps,
9
+ } from './types';
@@ -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
- <div
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
- <div className="text-sm text-sec-600">
65
- {message}
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
- * <div className="flex items-center gap-2">
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
- * </div>
36
+ * </>
37
37
  * );
38
38
  * }
39
39
  * ```
@@ -44,12 +44,12 @@
44
44
  *
45
45
  * function FormExample() {
46
46
  * return (
47
- * <div className="flex items-center gap-2">
47
+ * <>
48
48
  * <Switch id="terms" />
49
49
  * <Label htmlFor="terms">
50
50
  * I agree to the terms and conditions
51
51
  * </Label>
52
- * </div>
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
- * <div>Content for tab 1</div>
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
- * <div className="space-y-1">
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
- * </div>
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
- expect(screen.getByText('Loading...')).toBeInTheDocument();
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
- const avatarPlaceholder = screen.getByRole('button').querySelector('.animate-pulse');
585
- expect(avatarPlaceholder).toBeInTheDocument();
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
- expect(screen.getByRole('status')).toBeInTheDocument();
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
- const statusElement = screen.getByRole('status');
599
- expect(statusElement).toHaveAttribute('aria-live', 'polite');
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
- expect(screen.getByLabelText('Loading user menu')).toBeInTheDocument();
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
- * <div className="flex items-center gap-4">
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
- * </div>
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
- <div className="flex flex-col space-y-1">
183
- <p className="font-medium">{userInfo.displayName}</p>
184
- <p className="text-muted-foreground">{userInfo.email}</p>
185
- </div>
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
- <div className="relative inline-block text-left">
226
- <button
227
- type="button"
228
- disabled
229
- className="flex items-center space-x-2 px-3 py-2 text-sm font-medium text-muted-foreground bg-muted border border-input rounded-md"
230
- >
231
- <div className="w-6 h-6 rounded-full bg-muted animate-pulse" />
232
- <span className="truncate max-w-[150px]">Loading...</span>
233
- <ChevronDown className="w-4 h-4 text-muted-foreground" />
234
- </button>
235
- <div role="status" aria-label="Loading user menu" aria-live="polite" className="w-6 h-6 rounded-full bg-muted animate-pulse" />
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
 
@@ -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
- it('should export useSecureDataAccess', () => {
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',
@@ -33,9 +33,8 @@ export type { UseAddressAutocompleteOptions, UseAddressAutocompleteReturn } from
33
33
 
34
34
  // === ORGANISATION HOOKS ===
35
35
  export { useOrganisationPermissions } from './useOrganisationPermissions';
36
- export { useSecureDataAccess } from './useSecureDataAccess';
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;