@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,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;
@@ -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;
@@ -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
  *
@@ -87,6 +87,9 @@
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
@@ -359,6 +359,7 @@ export function FormField<
359
359
  type={type}
360
360
  placeholder={placeholder}
361
361
  data-testid={testId}
362
+ aria-label={label || placeholder || name}
362
363
  className={cn(
363
364
  "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
364
365
  fieldError && "border-destructive focus-visible:ring-destructive"
@@ -42,10 +42,10 @@
42
42
  * ]}
43
43
  * currentPath="/dashboard"
44
44
  * actions={
45
- * <div className="flex gap-2">
45
+ * <>
46
46
  * <Button variant="outline">Export</Button>
47
47
  * <Button>New Item</Button>
48
- * </div>
48
+ * </>
49
49
  * }
50
50
  * user={currentUser}
51
51
  * onSignOut={handleSignOut}
@@ -199,10 +199,10 @@ export interface HeaderProps {
199
199
  *
200
200
  * function HeaderWithActions() {
201
201
  * const customActions = (
202
- * <div className="flex items-center gap-2">
202
+ * <>
203
203
  * <Button variant="outline" size="sm">Export</Button>
204
204
  * <Button size="sm">New Item</Button>
205
- * </div>
205
+ * </>
206
206
  * );
207
207
  *
208
208
  * return (
@@ -238,6 +238,13 @@ export interface HeaderProps {
238
238
  *
239
239
  * @since 0.1.0
240
240
  */
241
+ /**
242
+ * Header component for application layouts.
243
+ * Provides navigation, user menu, organisation/event selectors, and customizable branding.
244
+ *
245
+ * @param props - Header configuration
246
+ * @returns The rendered header
247
+ */
241
248
  export function Header({
242
249
  logoUrl,
243
250
  logoAlt = 'Logo',
@@ -278,7 +285,7 @@ export function Header({
278
285
  "w-full border-b border-main-200 h-16 shadow-sm bg-main-100 ",
279
286
  className
280
287
  )} role="banner">
281
- <nav className="px-4 w-[min(var(--app-width),100%)] mx-auto flex items-center gap-4 h-full">
288
+ <nav className="px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_1fr_auto_auto_auto_auto] items-center gap-4 h-full">
282
289
  {/* Logo */}
283
290
  {logo ? (
284
291
  logoHref ? (
@@ -333,10 +340,7 @@ export function Header({
333
340
  itemsPreFiltered={true}
334
341
  />
335
342
  )}
336
-
337
343
 
338
- {/* Right side: Organisation Selector, Event Selector, Actions, and User Menu */}
339
- <div className="flex items-center gap-4 ml-auto">
340
344
  {/* Organisation Selector - Only show if user has organisations */}
341
345
  {showOrgSelector ? (
342
346
  <OrganisationSelectorConditional />
@@ -346,7 +350,15 @@ export function Header({
346
350
  {showEventSelector ? (
347
351
  <EventSelector
348
352
  placeholder="Select event"
349
- className="w-96"
353
+ className={cn(
354
+ "w-96",
355
+ // If both org selector and actions exist, EventSelector uses 1 column
356
+ // If only one exists, EventSelector spans 2 columns
357
+ // If neither exists, EventSelector spans 3 columns
358
+ showOrgSelector && actions ? "col-span-1" :
359
+ showOrgSelector || actions ? "col-span-2" :
360
+ "col-span-3"
361
+ )}
350
362
  data-testid="event-selector"
351
363
  />
352
364
  ) : null}
@@ -367,7 +379,6 @@ export function Header({
367
379
  />
368
380
  )
369
381
  )}
370
- </div>
371
382
 
372
383
  </nav>
373
384
  </header>
@@ -420,14 +420,14 @@ describe('InputGroup Component', () => {
420
420
  // Accessibility tests
421
421
  describe('Accessibility', () => {
422
422
  it('forwards ref correctly', () => {
423
- const ref = React.createRef<HTMLDivElement>();
423
+ const ref = React.createRef<HTMLFieldSetElement>();
424
424
  renderWithProviders(
425
425
  <InputGroup ref={ref}>
426
426
  <Input placeholder="Input 1" />
427
427
  </InputGroup>
428
428
  );
429
429
 
430
- expect(ref.current).toBeInstanceOf(HTMLDivElement);
430
+ expect(ref.current).toBeInstanceOf(HTMLFieldSetElement);
431
431
  });
432
432
 
433
433
  it('maintains proper focus order', async () => {
@@ -55,6 +55,10 @@ import { cn } from '../../utils/core/cn';
55
55
  // BASE INPUT COMPONENT
56
56
  // ============================================================================
57
57
 
58
+ /**
59
+ * Props for the Input component.
60
+ * Extends standard input HTML attributes.
61
+ */
58
62
  export interface InputProps
59
63
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
60
64
  /**
@@ -136,7 +140,7 @@ Input.displayName = 'Input';
136
140
  // INPUT GROUP COMPONENT
137
141
  // ============================================================================
138
142
 
139
- export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
143
+ export interface InputGroupProps extends React.HTMLAttributes<HTMLFieldSetElement> {
140
144
  /** Child elements to be rendered in the group */
141
145
  children: React.ReactNode;
142
146
  /** Layout orientation of the input group */
@@ -165,7 +169,7 @@ export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
165
169
  * </InputGroup>
166
170
  * ```
167
171
  */
168
- export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
172
+ export const InputGroup = React.forwardRef<HTMLFieldSetElement, InputGroupProps>(
169
173
  ({ className, children, orientation = 'vertical', spacing = 'md', ...props }, ref) => {
170
174
  const spacingClasses = {
171
175
  sm: orientation === 'horizontal' ? 'space-x-2' : 'space-y-2',
@@ -174,7 +178,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
174
178
  };
175
179
 
176
180
  return (
177
- <div
181
+ <fieldset
178
182
  ref={ref}
179
183
  className={cn(
180
184
  'flex',
@@ -185,7 +189,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
185
189
  {...props}
186
190
  >
187
191
  {children}
188
- </div>
192
+ </fieldset>
189
193
  );
190
194
  }
191
195
  );
@@ -382,10 +382,10 @@ describe('LoadingSpinner Component', () => {
382
382
 
383
383
  it('works within a card or container', () => {
384
384
  renderWithProviders(
385
- <div className="card">
385
+ <section className="card">
386
386
  <h2>Loading Content</h2>
387
387
  <LoadingSpinner size="lg" />
388
- </div>
388
+ </section>
389
389
  );
390
390
 
391
391
  const spinner = screen.getByRole('status');
@@ -397,11 +397,11 @@ describe('LoadingSpinner Component', () => {
397
397
 
398
398
  it('works with multiple instances', () => {
399
399
  renderWithProviders(
400
- <div>
400
+ <>
401
401
  <LoadingSpinner size="sm" />
402
402
  <LoadingSpinner size="md" />
403
403
  <LoadingSpinner size="lg" />
404
- </div>
404
+ </>
405
405
  );
406
406
 
407
407
  const spinners = screen.getAllByRole('status');
@@ -106,6 +106,10 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
106
106
  import { Alert, AlertDescription } from '../Alert/Alert';
107
107
  import { cn } from '../../utils/core/cn';
108
108
 
109
+ /**
110
+ * Props for the LoginForm component.
111
+ * Configures login form behavior, validation, and callbacks.
112
+ */
109
113
  export interface LoginFormProps {
110
114
  /** Callback invoked when the form is submitted */
111
115
  onSignIn: (data: { email: string; password: string }) => Promise<void>;