@jmruthers/pace-core 0.5.193 → 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 (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -25,10 +25,35 @@
25
25
  * <MyComponent />
26
26
  * </ErrorBoundary>
27
27
  *
28
+ * // Using global error handler (recommended for applications)
29
+ * import { ErrorBoundaryProvider, ErrorBoundary } from '@jmruthers/pace-core';
30
+ *
31
+ * // Setup once in main.tsx
32
+ * <ErrorBoundaryProvider
33
+ * defaultErrorHandler={(error, errorInfo, errorId, componentName) => {
34
+ * if (import.meta.env.DEV) {
35
+ * console.error(`[${componentName}] ErrorBoundary caught error:`, error, errorInfo);
36
+ * }
37
+ * errorTracking.captureException(error, {
38
+ * componentStack: errorInfo.componentStack,
39
+ * errorBoundary: true,
40
+ * errorId,
41
+ * componentName,
42
+ * });
43
+ * }}
44
+ * >
45
+ * <App />
46
+ * </ErrorBoundaryProvider>
47
+ *
48
+ * // Then use ErrorBoundary without onError prop - uses global handler
49
+ * <ErrorBoundary componentName="AppRoot">
50
+ * <AppContent />
51
+ * </ErrorBoundary>
52
+ *
28
53
  * // Error boundary with custom fallback
29
54
  * <ErrorBoundary
30
55
  * componentName="UserProfile"
31
- * fallback={<div>Something went wrong loading the profile.</div>}
56
+ * fallback={<section>Something went wrong loading the profile.</section>}
32
57
  * onError={(error, errorInfo, errorId) => {
33
58
  * console.log('Error caught:', errorId, error);
34
59
  * }}
@@ -58,6 +83,16 @@
58
83
  * </ErrorBoundary>
59
84
  * <Footer />
60
85
  * </ErrorBoundary>
86
+ *
87
+ * // Per-instance onError overrides global handler
88
+ * <ErrorBoundary
89
+ * componentName="SpecialCase"
90
+ * onError={(error, errorInfo, errorId) => {
91
+ * // Custom handling for this specific case - global handler won't be called
92
+ * }}
93
+ * >
94
+ * <SpecialComponent />
95
+ * </ErrorBoundary>
61
96
  * ```
62
97
  *
63
98
  * @accessibility
@@ -75,7 +110,7 @@
75
110
  * - Configurable error reporting
76
111
  *
77
112
  * @dependencies
78
- * - React 18+ - Component lifecycle
113
+ * - React 19+ - Component lifecycle
79
114
  * - Performance monitoring utilities
80
115
  * - Tailwind CSS - Styling
81
116
  */
@@ -120,6 +155,8 @@ export interface ErrorBoundaryProps {
120
155
  enableRetry?: boolean;
121
156
  /** Whether to enable error reporting */
122
157
  enableReporting?: boolean;
158
+ /** Internal: Global error handler from context (not part of public API) */
159
+ _globalErrorHandler?: (error: Error, errorInfo: React.ErrorInfo, errorId: string, componentName: string) => void;
123
160
  }
124
161
 
125
162
  /**
@@ -162,15 +199,16 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
162
199
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
163
200
  const { componentName = 'Unknown Component', onError, enableReporting = true } = this.props;
164
201
  const errorId = this.state.errorId!;
202
+ const componentNameForHandler = componentName || 'Unknown Component';
165
203
 
166
204
  this.setState({ errorInfo });
167
205
 
168
206
  // Enhanced logging with component name and error ID
169
- logger.error('ErrorBoundary', `[${componentName}] Caught error ${errorId}:`, error, errorInfo);
207
+ logger.error('ErrorBoundary', `[${componentNameForHandler}] Caught error ${errorId}:`, error, errorInfo);
170
208
 
171
209
  // Performance monitoring - track error occurrence
172
210
  performanceBudgetMonitor.measure('ERROR_BOUNDARY_TRIGGER', 1, {
173
- componentName,
211
+ componentName: componentNameForHandler,
174
212
  errorId,
175
213
  errorMessage: error.message,
176
214
  stack: error.stack?.substring(0, 200), // Truncated stack trace
@@ -178,12 +216,14 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
178
216
 
179
217
  // Report error if enabled
180
218
  if (enableReporting) {
181
- this.reportError(errorId, componentName);
219
+ this.reportError(errorId, componentNameForHandler);
182
220
  }
183
221
 
184
- // Call custom error handler if provided
222
+ // Call error handler: prefer prop onError, fall back to global handler from props
185
223
  if (onError) {
186
224
  onError(error, errorInfo, errorId);
225
+ } else if (this.props._globalErrorHandler) {
226
+ this.props._globalErrorHandler(error, errorInfo, errorId, componentNameForHandler);
187
227
  }
188
228
  }
189
229
 
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @file Error Boundary Context
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/ErrorBoundary
5
+ * @since 0.6.2
6
+ *
7
+ * Context provider for global error handler configuration in ErrorBoundary components.
8
+ * Allows applications to register a default error handler once, which is then used by
9
+ * all ErrorBoundary instances unless overridden.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * // Setup once in main.tsx
14
+ * <ErrorBoundaryProvider
15
+ * defaultErrorHandler={(error, errorInfo, errorId, componentName) => {
16
+ * if (import.meta.env.DEV) {
17
+ * console.error(`[${componentName}] ErrorBoundary caught error:`, error, errorInfo);
18
+ * }
19
+ * errorTracking.captureException(error, {
20
+ * componentStack: errorInfo.componentStack,
21
+ * errorBoundary: true,
22
+ * errorId,
23
+ * componentName,
24
+ * });
25
+ * }}
26
+ * >
27
+ * <App />
28
+ * </ErrorBoundaryProvider>
29
+ *
30
+ * // Usage - no onError needed, uses global handler
31
+ * <ErrorBoundary componentName="AppRoot">
32
+ * <AppContent />
33
+ * </ErrorBoundary>
34
+ * ```
35
+ */
36
+
37
+ import React, { createContext, useContext, ReactNode } from 'react';
38
+
39
+ /**
40
+ * Type definition for the global error handler function
41
+ * @public
42
+ */
43
+ export type GlobalErrorHandler = (
44
+ error: Error,
45
+ errorInfo: React.ErrorInfo,
46
+ errorId: string,
47
+ componentName: string
48
+ ) => void;
49
+
50
+ /**
51
+ * Context value type for ErrorBoundary configuration
52
+ * @internal
53
+ */
54
+ interface ErrorBoundaryContextType {
55
+ /** Global error handler that will be used by all ErrorBoundary instances */
56
+ defaultErrorHandler?: GlobalErrorHandler;
57
+ }
58
+
59
+ /**
60
+ * Context for ErrorBoundary global configuration
61
+ * @internal
62
+ */
63
+ const ErrorBoundaryContext = createContext<ErrorBoundaryContextType | undefined>(undefined);
64
+
65
+ /**
66
+ * Props for ErrorBoundaryProvider component
67
+ * @public
68
+ */
69
+ export interface ErrorBoundaryProviderProps {
70
+ /** Children to wrap with the provider */
71
+ children: ReactNode;
72
+ /** Global error handler that will be used by all ErrorBoundary instances unless overridden */
73
+ defaultErrorHandler?: GlobalErrorHandler;
74
+ }
75
+
76
+ /**
77
+ * Provider component for ErrorBoundary global error handler configuration
78
+ *
79
+ * Wrap your application with this provider to set a default error handler that will
80
+ * be used by all ErrorBoundary instances unless they provide their own onError prop.
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * <ErrorBoundaryProvider
85
+ * defaultErrorHandler={(error, errorInfo, errorId, componentName) => {
86
+ * errorTracking.captureException(error, {
87
+ * componentStack: errorInfo.componentStack,
88
+ * errorBoundary: true,
89
+ * errorId,
90
+ * componentName,
91
+ * });
92
+ * }}
93
+ * >
94
+ * <App />
95
+ * </ErrorBoundaryProvider>
96
+ * ```
97
+ *
98
+ * @public
99
+ */
100
+ /**
101
+ * Error boundary provider component.
102
+ * Provides global error handling configuration to child ErrorBoundary components.
103
+ *
104
+ * @param props - Error boundary provider configuration
105
+ * @returns The error boundary provider
106
+ */
107
+ export function ErrorBoundaryProvider({
108
+ children,
109
+ defaultErrorHandler,
110
+ }: ErrorBoundaryProviderProps) {
111
+ const contextValue: ErrorBoundaryContextType = {
112
+ defaultErrorHandler,
113
+ };
114
+
115
+ return (
116
+ <ErrorBoundaryContext.Provider value={contextValue}>
117
+ {children}
118
+ </ErrorBoundaryContext.Provider>
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Hook to access ErrorBoundary context
124
+ * @internal
125
+ */
126
+ export function useErrorBoundaryContext(): ErrorBoundaryContextType | undefined {
127
+ return useContext(ErrorBoundaryContext);
128
+ }
129
+
@@ -2,7 +2,32 @@
2
2
  * @file Error Boundary exports
3
3
  */
4
4
 
5
- export { ErrorBoundary } from './ErrorBoundary';
5
+ // Re-export ErrorBoundary with automatic context support
6
+ import { ErrorBoundary as ErrorBoundaryClass } from './ErrorBoundary';
7
+ import { useErrorBoundaryContext } from './ErrorBoundaryContext';
8
+ import React from 'react';
9
+ import type { ErrorBoundaryProps } from './ErrorBoundary';
10
+
11
+ // Export types and provider
6
12
  export type { ErrorBoundaryProps, ErrorBoundaryState } from './ErrorBoundary';
7
- import { ErrorBoundary } from './ErrorBoundary';
13
+ export { ErrorBoundaryProvider } from './ErrorBoundaryContext';
14
+ export type { ErrorBoundaryProviderProps, GlobalErrorHandler } from './ErrorBoundaryContext';
15
+
16
+ /**
17
+ * ErrorBoundary component with automatic context support
18
+ * This wrapper automatically uses the global error handler from ErrorBoundaryProvider
19
+ * if no onError prop is provided.
20
+ */
21
+ export const ErrorBoundary = React.forwardRef<
22
+ ErrorBoundaryClass,
23
+ Omit<ErrorBoundaryProps, '_globalErrorHandler'>
24
+ >((props, ref) => {
25
+ const context = useErrorBoundaryContext();
26
+ const globalErrorHandler = context?.defaultErrorHandler;
27
+
28
+ return React.createElement(ErrorBoundaryClass, { ...props, ref, _globalErrorHandler: globalErrorHandler });
29
+ });
30
+
31
+ ErrorBoundary.displayName = 'ErrorBoundary';
32
+
8
33
  export default ErrorBoundary;
@@ -80,7 +80,7 @@
80
80
  * - Button component - Retry functionality
81
81
  * - Alert component - Error display
82
82
  * - LoadingSpinner - Loading states
83
- * - React 18+ - Hooks and effects
83
+ * - React 19+ - Hooks and effects
84
84
  * - Tailwind CSS - Styling
85
85
  */
86
86
 
@@ -95,6 +95,9 @@ import { useEffect, useMemo, useRef } from 'react';
95
95
  import { cn } from '../../utils/core/cn';
96
96
  import { logger } from '../../utils/core/logger';
97
97
 
98
+ /**
99
+ * Props for the EventSelector component.
100
+ */
98
101
  export interface EventSelectorProps {
99
102
  /** Placeholder text for the dropdown */
100
103
  placeholder?: string;
@@ -49,7 +49,7 @@ vi.mock('../../utils/storage/helpers', () => ({
49
49
  }));
50
50
 
51
51
  // Helper to render with UnifiedAuthProvider
52
- const renderWithUnifiedAuth = (ui: React.ReactElement) => {
52
+ const renderWithUnifiedAuth = (ui: React.ReactElement<any>) => {
53
53
  return renderWithProviders(
54
54
  <UnifiedAuthProvider
55
55
  supabaseClient={supabase}
@@ -64,7 +64,7 @@ const renderWithUnifiedAuth = (ui: React.ReactElement) => {
64
64
  );
65
65
  };
66
66
 
67
- const renderWithPublicContext = (ui: React.ReactElement, value: any = null) => {
67
+ const renderWithPublicContext = (ui: React.ReactElement<any>, value: any = null) => {
68
68
  const Context = publicPageContextStore.value ?? React.createContext(null);
69
69
 
70
70
  return renderWithProviders(
@@ -192,10 +192,15 @@ function FileDisplayContent({
192
192
 
193
193
  const handleDeleteConfirm = async () => {
194
194
  setDeleteDialogOpen(false);
195
- if (onDelete) {
196
- await onDelete();
195
+ try {
196
+ if (onDelete) {
197
+ await onDelete();
198
+ }
199
+ setImageError(false);
200
+ } catch (error) {
201
+ // Error handling is delegated to onDelete callback
202
+ setImageError(false);
197
203
  }
198
- setImageError(false);
199
204
  };
200
205
 
201
206
  const handleImageError = () => {
@@ -773,16 +778,10 @@ function FileDisplayAuthenticated({
773
778
  }: FileDisplayProps) {
774
779
  const { supabase } = useUnifiedAuth();
775
780
 
776
- if (!supabase) {
777
- return (
778
- <figure className={className} title="Error">
779
- <p className={getFallbackClasses(fallbackSize || 'md')}>
780
- Supabase client not available in authenticated context
781
- </p>
782
- </figure>
783
- );
784
- }
781
+ // Consolidated state for displayOnly mode - must be before early return
782
+ const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState<FileReference | null>(null);
785
783
 
784
+ // Call hooks before any early returns - hooks must handle null supabase gracefully
786
785
  const {
787
786
  fileUrl,
788
787
  fileReference,
@@ -797,20 +796,17 @@ function FileDisplayAuthenticated({
797
796
  record_id,
798
797
  organisation_id,
799
798
  category,
800
- { supabase }
799
+ { supabase: supabase || null }
801
800
  );
802
-
803
- // Consolidated state for displayOnly mode
804
- const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState<FileReference | null>(null);
805
801
 
806
802
  // Use fileUrls map if available, otherwise use useFileUrl hook
807
803
  const displayOnlyFileUrlFromMap = displayOnlyFileReference ? fileUrls.get(displayOnlyFileReference.id) : null;
808
804
  const displayOnlyFileUrlHook = useFileUrl(
809
805
  displayOnlyFileReference && !displayOnlyFileUrlFromMap ? displayOnlyFileReference : null,
810
806
  {
811
- supabase,
807
+ supabase: supabase || null,
812
808
  organisation_id,
813
- autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference
809
+ autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference && !!supabase
814
810
  }
815
811
  );
816
812
  const displayOnlyFileUrl = displayOnlyFileUrlFromMap || displayOnlyFileUrlHook.url;
@@ -831,6 +827,17 @@ function FileDisplayAuthenticated({
831
827
  }
832
828
  }, [displayOnly, category, fileReferences, fileUrls]);
833
829
 
830
+ // Early return check after all hooks are called
831
+ if (!supabase) {
832
+ return (
833
+ <figure className={className} title="Error">
834
+ <p className={getFallbackClasses(fallbackSize || 'md')}>
835
+ Supabase client not available in authenticated context
836
+ </p>
837
+ </figure>
838
+ );
839
+ }
840
+
834
841
  // Delete operation - implementation pending
835
842
  const handleDelete = async () => {
836
843
  // TODO: Implement delete via FileReferenceService when delete functionality is needed
@@ -906,6 +913,13 @@ function FileDisplayAuthenticated({
906
913
  * @param props.category - Optional category filter. When specified, only displays files matching this category and uses single file display variant.
907
914
  * @returns React element with file display
908
915
  */
916
+ /**
917
+ * File display component.
918
+ * Renders files from the file reference system with support for previews, downloads, and public/private access.
919
+ *
920
+ * @param props - File display configuration
921
+ * @returns The rendered file display
922
+ */
909
923
  export function FileDisplay({
910
924
  table_name,
911
925
  record_id,
@@ -15,6 +15,10 @@ import { getCurrentAppName } from '../../utils/app/appNameResolver';
15
15
  import { getAppId } from '../../utils/app/appIdResolver';
16
16
  import { assertAppId } from '../../types/core';
17
17
 
18
+ /**
19
+ * Props for the FileUpload component.
20
+ * Configures file upload behavior including storage location, validation, and callbacks.
21
+ */
18
22
  export interface FileUploadProps {
19
23
  supabase: SupabaseClient;
20
24
  table_name: string;
@@ -71,6 +75,15 @@ export function FileUpload({
71
75
  onProgress,
72
76
  children
73
77
  }: FileUploadProps) {
78
+ // Validate pageContext early - required prop
79
+ if (!pageContext) {
80
+ const errorMsg = 'pageContext is required for FileUpload component. This is used for permission checks.';
81
+ if (import.meta.env.MODE === 'development') {
82
+ console.error('[FileUpload]', errorMsg);
83
+ }
84
+ throw new Error(errorMsg);
85
+ }
86
+
74
87
  const [isDragging, setIsDragging] = useState(false);
75
88
  const [uploadStates, setUploadStates] = useState<Map<string, FileUploadState>>(new Map());
76
89
  const [resolvedAppId, setResolvedAppId] = useState<string | null>(app_id || null);
@@ -286,6 +299,12 @@ export function FileUpload({
286
299
  throw new Error(errorMsg);
287
300
  }
288
301
 
302
+ // Validate pageContext before upload
303
+ if (!pageContext) {
304
+ const errorMsg = 'pageContext is required for file upload. This is used for permission checks.';
305
+ throw new Error(errorMsg);
306
+ }
307
+
289
308
  const result = await uploadFile({
290
309
  table_name,
291
310
  record_id,
@@ -294,7 +313,7 @@ export function FileUpload({
294
313
  app_id: resolvedAppId ? assertAppId(resolvedAppId) : assertAppId(''),
295
314
  category,
296
315
  folder,
297
- pageContext,
316
+ pageContext: pageContext,
298
317
  event_id,
299
318
  is_public: isPublic
300
319
  }, file);
@@ -393,7 +412,7 @@ export function FileUpload({
393
412
  onUploadError?.(errorMessage, file);
394
413
  }
395
414
  }
396
- }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);
415
+ }, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError, pageContext]);
397
416
 
398
417
  const handleDragOver = useCallback((e: React.DragEvent) => {
399
418
  e.preventDefault();
@@ -475,6 +494,7 @@ export function FileUpload({
475
494
  className="hidden"
476
495
  disabled={isDisabled}
477
496
  data-testid="file-input"
497
+ aria-label={accept ? `Upload file${multiple ? 's' : ''} (${accept})` : `Upload file${multiple ? 's' : ''}`}
478
498
  />
479
499
  <div className="text-sec-600">
480
500
  {isResolvingAppId ? (
@@ -82,7 +82,7 @@ describe('Footer Component', () => {
82
82
  it('renders with children content', () => {
83
83
  renderWithProviders(
84
84
  <Footer>
85
- <div data-testid="custom-content">Custom footer content</div>
85
+ <section data-testid="custom-content">Custom footer content</section>
86
86
  </Footer>
87
87
  );
88
88
 
@@ -163,7 +163,7 @@ describe('Footer Component', () => {
163
163
  it('renders content in proper semantic structure', () => {
164
164
  renderWithProviders(
165
165
  <Footer>
166
- <div>Custom content</div>
166
+ <section>Custom content</section>
167
167
  </Footer>
168
168
  );
169
169
 
@@ -175,7 +175,7 @@ describe('Footer Component', () => {
175
175
  it('renders logo before children content', () => {
176
176
  renderWithProviders(
177
177
  <Footer logo="/logo.png">
178
- <div data-testid="children">Children content</div>
178
+ <section data-testid="children">Children content</section>
179
179
  </Footer>
180
180
  );
181
181
 
@@ -189,7 +189,7 @@ describe('Footer Component', () => {
189
189
  it('renders copyright text after children content', () => {
190
190
  renderWithProviders(
191
191
  <Footer>
192
- <div data-testid="children">Children content</div>
192
+ <section data-testid="children">Children content</section>
193
193
  </Footer>
194
194
  );
195
195
 
@@ -380,7 +380,7 @@ describe('Footer Component', () => {
380
380
  logo="/test-logo.png"
381
381
  copyright="Custom copyright text"
382
382
  >
383
- <div>Test children</div>
383
+ <section>Test children</section>
384
384
  </Footer>
385
385
  );
386
386
 
@@ -398,27 +398,27 @@ describe('Footer Component', () => {
398
398
  it('works with complex children content', () => {
399
399
  renderWithProviders(
400
400
  <Footer>
401
- <div className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
402
- <div>
401
+ <section className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
402
+ <section>
403
403
  <h3 className="font-semibold mb-2">About Us</h3>
404
404
  <p className="text-sm text-muted-foreground">
405
405
  We provide innovative solutions for modern businesses.
406
406
  </p>
407
- </div>
408
- <div>
407
+ </section>
408
+ <section>
409
409
  <h3 className="font-semibold mb-2">Contact</h3>
410
410
  <p className="text-sm text-muted-foreground">
411
411
  Email: info@company.com
412
412
  </p>
413
- </div>
414
- <div>
413
+ </section>
414
+ <section>
415
415
  <h3 className="font-semibold mb-2">Follow Us</h3>
416
- <div className="flex gap-2">
416
+ <nav className="flex gap-2">
417
417
  <a href="#" className="text-muted-foreground hover:text-foreground">Twitter</a>
418
418
  <a href="#" className="text-muted-foreground hover:text-foreground">LinkedIn</a>
419
- </div>
420
- </div>
421
- </div>
419
+ </nav>
420
+ </section>
421
+ </section>
422
422
  </Footer>
423
423
  );
424
424
 
@@ -463,7 +463,7 @@ describe('Footer Component', () => {
463
463
  logo="/logo.png"
464
464
  className="custom-footer"
465
465
  >
466
- <div data-testid="custom-content">Custom footer content</div>
466
+ <section data-testid="custom-content">Custom footer content</section>
467
467
  </Footer>
468
468
  );
469
469
 
@@ -47,28 +47,28 @@
47
47
  *
48
48
  * // Footer with custom content
49
49
  * <Footer companyName="My Company">
50
- * <div className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
51
- * <div>
50
+ * <section className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
51
+ * <section>
52
52
  * <h3 className="font-semibold mb-2">About Us</h3>
53
53
  * <p className="text-sm text-muted-foreground">
54
54
  * We provide innovative solutions for modern businesses.
55
55
  * </p>
56
- * </div>
57
- * <div>
56
+ * </section>
57
+ * <section>
58
58
  * <h3 className="font-semibold mb-2">Contact</h3>
59
59
  * <p className="text-sm text-muted-foreground">
60
60
  * Email: info@mycompany.com<br />
61
61
  * Phone: (555) 123-4567
62
62
  * </p>
63
- * </div>
64
- * <div>
63
+ * </section>
64
+ * <section>
65
65
  * <h3 className="font-semibold mb-2">Follow Us</h3>
66
- * <div className="flex gap-2">
66
+ * <nav className="flex gap-2">
67
67
  * <a href="#" className="text-muted-foreground hover:text-foreground">Twitter</a>
68
68
  * <a href="#" className="text-muted-foreground hover:text-foreground">LinkedIn</a>
69
- * </div>
70
- * </div>
71
- * </div>
69
+ * </nav>
70
+ * </section>
71
+ * </section>
72
72
  * </Footer>
73
73
  * ```
74
74
  *
@@ -81,12 +81,15 @@
81
81
  * - Clear link identification
82
82
  *
83
83
  * @dependencies
84
- * - React 18+ - Component framework
84
+ * - React 19+ - Component framework
85
85
  * - Tailwind CSS - Styling
86
86
  */
87
87
  import React from 'react';
88
88
  import { cn } from '../../utils/core/cn';
89
89
 
90
+ /**
91
+ * Props for the Footer component.
92
+ */
90
93
  export interface FooterProps {
91
94
  /**
92
95
  * Company or organization name
@@ -138,7 +141,7 @@ export interface FooterProps {
138
141
  *
139
142
  * // With children
140
143
  * <Footer>
141
- * <div>Custom footer content</div>
144
+ * <section>Custom footer content</section>
142
145
  * </Footer>
143
146
  *
144
147
  * // With logo and copyright