@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
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  description: Enforce testing framework consistency and standards for consuming apps
3
3
  globs: ["**/*.{test,spec}.{ts,tsx}"]
4
- alwaysApply: true
5
- paceCoreVersion: "0.5.x"
6
- rulesVersion: "2025-01-15"
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
7
  ---
8
8
  # Testing Standards Guide
9
9
 
@@ -25,24 +25,18 @@ npm run test:coverage
25
25
  **MUST use React Testing Library + userEvent for all component tests.**
26
26
 
27
27
  ```tsx
28
- // ✅ CORRECT - React Testing Library
28
+ // ✅ CORRECT: React Testing Library + userEvent
29
29
  import { render, screen } from '@testing-library/react';
30
30
  import userEvent from '@testing-library/user-event';
31
- import { Button } from '@jmruthers/pace-core';
32
-
33
31
  test('button clicks work', async () => {
34
32
  const user = userEvent.setup();
35
33
  const handleClick = vi.fn();
36
-
37
34
  render(<Button onClick={handleClick}>Click me</Button>);
38
-
39
35
  await user.click(screen.getByRole('button', { name: /click me/i }));
40
-
41
36
  expect(handleClick).toHaveBeenCalledTimes(1);
42
37
  });
43
38
 
44
- // ❌ WRONG - Enzyme or other testing libraries
45
- import { shallow } from 'enzyme';
39
+ // ❌ WRONG: Enzyme or other testing libraries
46
40
  ```
47
41
 
48
42
  ## MUST: Colocate Tests
@@ -94,21 +88,15 @@ export default defineConfig({
94
88
  **Tests MUST focus on what users see and do:**
95
89
 
96
90
  ```tsx
97
- // ❌ WRONG - Testing implementation
98
- test('calls setState', () => {
99
- const component = render(<Counter />);
100
- expect(component.state.count).toBe(0);
101
- });
91
+ // ❌ WRONG: Testing implementation (component.state.count)
92
+ test('calls setState', () => { const component = render(<Counter />); expect(component.state.count).toBe(0); });
102
93
 
103
- // ✅ CORRECT - Testing user behavior
94
+ // ✅ CORRECT: Testing user behavior (what user sees and does)
104
95
  test('displays count and increments on button click', async () => {
105
96
  const user = userEvent.setup();
106
97
  render(<Counter />);
107
-
108
98
  expect(screen.getByText('Count: 0')).toBeInTheDocument();
109
-
110
99
  await user.click(screen.getByRole('button', { name: /increment/i }));
111
-
112
100
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
113
101
  });
114
102
  ```
@@ -118,14 +106,11 @@ test('displays count and increments on button click', async () => {
118
106
  **MUST prefer accessible queries (byRole, byLabelText, etc.):**
119
107
 
120
108
  ```tsx
121
- // ✅ CORRECT - Accessible queries
109
+ // ✅ CORRECT: Accessible queries (byRole, byLabelText, byText)
122
110
  screen.getByRole('button', { name: /submit/i });
123
111
  screen.getByLabelText(/email address/i);
124
- screen.getByText(/welcome/i);
125
112
 
126
- // ❌ AVOID - Non-accessible queries (use as last resort)
127
- screen.getByTestId('submit-button');
128
- screen.getByClassName('btn-primary');
113
+ // ❌ AVOID: Non-accessible queries (getByTestId, getByClassName - use as last resort)
129
114
  ```
130
115
 
131
116
  ## SHOULD: Test Critical Paths
@@ -174,19 +159,10 @@ describe('EventCard', () => {
174
159
  **MUST NOT mock unless necessary:**
175
160
 
176
161
  ```tsx
177
- // ❌ WRONG - Unnecessary mock
178
- const mockFetch = vi.fn();
179
- global.fetch = mockFetch;
180
-
181
- // ✅ CORRECT - Use real implementation or MSW
162
+ // ❌ WRONG: Unnecessary mock (global.fetch = mockFetch)
163
+ // CORRECT: Use real implementation or MSW
182
164
  import { server } from './mocks/server';
183
- import { rest } from 'msw';
184
-
185
- server.use(
186
- rest.get('/api/events', (req, res, ctx) => {
187
- return res(ctx.json([{ id: '1', name: 'Event' }]));
188
- })
189
- );
165
+ server.use(rest.get('/api/events', (req, res, ctx) => res(ctx.json([{ id: '1', name: 'Event' }]))));
190
166
  ```
191
167
 
192
168
  ## MUST: Test Async Code Properly
@@ -194,16 +170,11 @@ server.use(
194
170
  **MUST handle async operations correctly:**
195
171
 
196
172
  ```tsx
197
- // ✅ CORRECT - Async testing
173
+ // ✅ CORRECT: Async testing with waitFor
198
174
  test('loads and displays events', async () => {
199
175
  render(<EventList />);
200
-
201
176
  expect(screen.getByText(/loading/i)).toBeInTheDocument();
202
-
203
- await waitFor(() => {
204
- expect(screen.getByText('Event 1')).toBeInTheDocument();
205
- });
206
-
177
+ await waitFor(() => expect(screen.getByText('Event 1')).toBeInTheDocument());
207
178
  expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
208
179
  });
209
180
  ```
@@ -213,11 +184,8 @@ test('loads and displays events', async () => {
213
184
  **MUST clean up resources:**
214
185
 
215
186
  ```tsx
216
- // ✅ CORRECT - Cleanup
217
- afterEach(() => {
218
- cleanup();
219
- vi.clearAllMocks();
220
- });
187
+ // ✅ CORRECT: Cleanup after tests
188
+ afterEach(() => { cleanup(); vi.clearAllMocks(); });
221
189
  ```
222
190
 
223
191
  ## SHOULD: Use Test Utilities
@@ -225,23 +193,11 @@ afterEach(() => {
225
193
  **SHOULD create reusable test utilities:**
226
194
 
227
195
  ```tsx
228
- // test-utils.tsx
229
- import { render } from '@testing-library/react';
230
- import { UnifiedAuthProvider } from '@jmruthers/pace-core';
231
-
196
+ // ✅ CORRECT: Reusable test utilities
232
197
  export function renderWithProviders(ui: React.ReactElement) {
233
- return render(
234
- <UnifiedAuthProvider supabaseClient={mockSupabase} appName="Test App">
235
- {ui}
236
- </UnifiedAuthProvider>
237
- );
198
+ return render(<UnifiedAuthProvider supabaseClient={mockSupabase} appName="Test App">{ui}</UnifiedAuthProvider>);
238
199
  }
239
-
240
- // Usage
241
- test('component works with providers', () => {
242
- renderWithProviders(<MyComponent />);
243
- // ...
244
- });
200
+ // Usage: renderWithProviders(<MyComponent />);
245
201
  ```
246
202
 
247
203
  ## MUST: Include Timeout Parameters
@@ -249,12 +205,9 @@ test('component works with providers', () => {
249
205
  **Tests MUST include timeout parameters to prevent hanging:**
250
206
 
251
207
  ```tsx
252
- // ✅ CORRECT - With timeout
208
+ // ✅ CORRECT: Include timeout parameters to prevent hanging
253
209
  test('async operation completes', async () => {
254
- await waitFor(
255
- () => expect(screen.getByText('Loaded')).toBeInTheDocument(),
256
- { timeout: 5000 }
257
- );
210
+ await waitFor(() => expect(screen.getByText('Loaded')).toBeInTheDocument(), { timeout: 5000 });
258
211
  }, { timeout: 10000 });
259
212
  ```
260
213
 
@@ -2,8 +2,8 @@
2
2
  description: Standardized templates for bug reports and feature requests for pace-core
3
3
  globs: []
4
4
  alwaysApply: false
5
- paceCoreVersion: "0.5.x"
6
- rulesVersion: "2025-01-15"
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
7
  ---
8
8
  # Bug Reports and Feature Requests Guide
9
9
 
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  description: Enforce code quality standards including TypeScript, ESLint, formatting, performance, and accessibility
3
3
  globs: ["src/**/*.{ts,tsx,js,jsx}"]
4
- alwaysApply: true
5
- paceCoreVersion: "0.5.x"
6
- rulesVersion: "2025-01-15"
4
+ alwaysApply: false
5
+ paceCoreVersion: "0.6.x"
6
+ rulesVersion: "2025-01-28"
7
7
  ---
8
8
  # Code Quality Guide
9
9
 
@@ -36,27 +36,17 @@ This guide enforces code quality standards to ensure maintainable, performant, a
36
36
  **MUST NOT use `any` type. Use `unknown` if type is truly unknown:**
37
37
 
38
38
  ```tsx
39
- // ❌ WRONG - Using any
40
- function processData(data: any) {
41
- return data.value;
42
- }
39
+ // ❌ WRONG: Using any
40
+ function processData(data: any) { return data.value; }
43
41
 
44
- // ✅ CORRECT - Using unknown with type guard
42
+ // ✅ CORRECT: Using unknown with type guard or proper types
45
43
  function processData(data: unknown) {
46
44
  if (typeof data === 'object' && data !== null && 'value' in data) {
47
45
  return (data as { value: string }).value;
48
46
  }
49
47
  throw new Error('Invalid data');
50
48
  }
51
-
52
- // ✅ CORRECT - Using proper types
53
- interface Data {
54
- value: string;
55
- }
56
-
57
- function processData(data: Data) {
58
- return data.value;
59
- }
49
+ // Or: interface Data { value: string; } function processData(data: Data) { return data.value; }
60
50
  ```
61
51
 
62
52
  ### MUST: Use Discriminated Unions
@@ -64,18 +54,11 @@ function processData(data: Data) {
64
54
  **MUST use discriminated unions instead of boolean flags:**
65
55
 
66
56
  ```tsx
67
- // ❌ WRONG - Boolean flags
68
- interface User {
69
- isAdmin: boolean;
70
- isGuest: boolean;
71
- // Confusing: what if both are true?
72
- }
57
+ // ❌ WRONG: Boolean flags (confusing: what if both are true?)
58
+ interface User { isAdmin: boolean; isGuest: boolean; }
73
59
 
74
- // ✅ CORRECT - Discriminated union
75
- type User =
76
- | { type: 'admin'; permissions: Permission[] }
77
- | { type: 'guest'; limitedAccess: boolean }
78
- | { type: 'user'; role: UserRole };
60
+ // ✅ CORRECT: Discriminated union
61
+ type User = { type: 'admin'; permissions: Permission[] } | { type: 'guest'; limitedAccess: boolean } | { type: 'user'; role: UserRole };
79
62
  ```
80
63
 
81
64
  ### SHOULD: Use ReadonlyArray
@@ -148,20 +131,10 @@ npm run format
148
131
  **SHOULD use React.memo, useMemo, useCallback appropriately:**
149
132
 
150
133
  ```tsx
151
- // ✅ CORRECT - Memoize expensive computations
152
- const expensiveValue = useMemo(() => {
153
- return computeExpensiveValue(data);
154
- }, [data]);
155
-
156
- // ✅ CORRECT - Memoize callbacks
157
- const handleClick = useCallback(() => {
158
- doSomething(id);
159
- }, [id]);
160
-
161
- // ✅ CORRECT - Memoize components
162
- const ExpensiveComponent = React.memo(({ data }) => {
163
- return <div>{/* ... */}</div>;
164
- });
134
+ // ✅ CORRECT: Memoize expensive computations, callbacks, and components
135
+ const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
136
+ const handleClick = useCallback(() => doSomething(id), [id]);
137
+ const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
165
138
  ```
166
139
 
167
140
  ### SHOULD: Avoid Unnecessary Re-renders
@@ -169,18 +142,12 @@ const ExpensiveComponent = React.memo(({ data }) => {
169
142
  **SHOULD avoid causing unnecessary re-renders:**
170
143
 
171
144
  ```tsx
172
- // ❌ WRONG - New object on every render
173
- function Component({ items }) {
174
- const config = { items, enabled: true }; // New object each render
175
- return <Child config={config} />;
176
- }
145
+ // ❌ WRONG: New object on every render (causes unnecessary re-renders)
146
+ function Component({ items }) { const config = { items, enabled: true }; return <Child config={config} />; }
177
147
 
178
- // ✅ CORRECT - Memoize object
148
+ // ✅ CORRECT: Memoize object
179
149
  function Component({ items }) {
180
- const config = useMemo(
181
- () => ({ items, enabled: true }),
182
- [items]
183
- );
150
+ const config = useMemo(() => ({ items, enabled: true }), [items]);
184
151
  return <Child config={config} />;
185
152
  }
186
153
  ```
@@ -190,17 +157,11 @@ function Component({ items }) {
190
157
  **SHOULD lazy load heavy components:**
191
158
 
192
159
  ```tsx
193
- // ✅ CORRECT - Lazy loading
160
+ // ✅ CORRECT: Lazy load heavy components
194
161
  import { lazy, Suspense } from 'react';
195
-
196
162
  const HeavyComponent = lazy(() => import('./HeavyComponent'));
197
-
198
163
  function App() {
199
- return (
200
- <Suspense fallback={<Loading />}>
201
- <HeavyComponent />
202
- </Suspense>
203
- );
164
+ return <Suspense fallback={<Loading />}><HeavyComponent /></Suspense>;
204
165
  }
205
166
  ```
206
167
 
@@ -211,11 +172,8 @@ function App() {
211
172
  **MUST use semantic HTML elements:**
212
173
 
213
174
  ```tsx
214
- // ❌ WRONG - Non-semantic
215
- <div onClick={handleClick}>Click me</div>
216
-
217
- // ✅ CORRECT - Semantic
218
- <button onClick={handleClick}>Click me</button>
175
+ // ❌ WRONG: Non-semantic (<div onClick={...}>)
176
+ // ✅ CORRECT: Semantic HTML (<button onClick={...}>)
219
177
  ```
220
178
 
221
179
  ### MUST: Provide ARIA Labels
@@ -223,7 +181,7 @@ function App() {
223
181
  **MUST provide ARIA labels for interactive elements:**
224
182
 
225
183
  ```tsx
226
- // ✅ CORRECT - ARIA labels
184
+ // ✅ CORRECT: Provide ARIA labels for interactive elements
227
185
  <button aria-label="Close dialog">×</button>
228
186
  <input aria-label="Search" type="search" />
229
187
  ```
@@ -233,17 +191,8 @@ function App() {
233
191
  **MUST ensure all interactive elements are keyboard accessible:**
234
192
 
235
193
  ```tsx
236
- // ✅ CORRECT - Keyboard accessible
237
- <button
238
- onClick={handleClick}
239
- onKeyDown={(e) => {
240
- if (e.key === 'Enter' || e.key === ' ') {
241
- handleClick();
242
- }
243
- }}
244
- >
245
- Click me
246
- </button>
194
+ // ✅ CORRECT: Ensure keyboard navigation (Enter or Space key)
195
+ <button onClick={handleClick} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleClick(); }}>Click me</button>
247
196
  ```
248
197
 
249
198
  ### MUST: Provide Focus Indicators
@@ -251,10 +200,8 @@ function App() {
251
200
  **MUST provide visible focus indicators:**
252
201
 
253
202
  ```tsx
254
- // ✅ CORRECT - Focus styles
255
- <button className="focus:outline-none focus:ring-2 focus:ring-main-500">
256
- Click me
257
- </button>
203
+ // ✅ CORRECT: Provide visible focus indicators
204
+ <button className="focus:outline-none focus:ring-2 focus:ring-main-500">Click me</button>
258
205
  ```
259
206
 
260
207
  ## Code Review Checklist
@@ -281,20 +228,12 @@ function App() {
281
228
  **Functions SHOULD be small and focused:**
282
229
 
283
230
  ```tsx
284
- // ❌ WRONG - Large function
285
- function processUserData(user) {
286
- // 100+ lines of logic
287
- }
288
-
289
- // ✅ CORRECT - Small, focused functions
290
- function validateUser(user: User): ValidationResult {
291
- // Validation logic
292
- }
293
-
294
- function transformUser(user: User): TransformedUser {
295
- // Transformation logic
296
- }
231
+ // ❌ WRONG: Large function (100+ lines, multiple responsibilities)
232
+ function processUserData(user) { /* 100+ lines of logic */ }
297
233
 
234
+ // ✅ CORRECT: Small, focused functions
235
+ function validateUser(user: User): ValidationResult { /* Validation logic */ }
236
+ function transformUser(user: User): TransformedUser { /* Transformation logic */ }
298
237
  function processUserData(user: User) {
299
238
  const validation = validateUser(user);
300
239
  if (!validation.valid) return validation;
@@ -307,24 +246,11 @@ function processUserData(user: User) {
307
246
  **Functions SHOULD have low cyclomatic complexity (< 10):**
308
247
 
309
248
  ```tsx
310
- // ❌ WRONG - High complexity
311
- function processData(data) {
312
- if (condition1) {
313
- if (condition2) {
314
- if (condition3) {
315
- // ... many nested conditions
316
- }
317
- }
318
- }
319
- }
249
+ // ❌ WRONG: High complexity (many nested conditions)
250
+ function processData(data) { if (condition1) { if (condition2) { if (condition3) { /* ... */ } } } }
320
251
 
321
- // ✅ CORRECT - Lower complexity
322
- function processData(data) {
323
- if (!condition1) return;
324
- if (!condition2) return;
325
- if (!condition3) return;
326
- // Process
327
- }
252
+ // ✅ CORRECT: Lower complexity (early returns)
253
+ function processData(data) { if (!condition1) return; if (!condition2) return; if (!condition3) return; /* Process */ }
328
254
  ```
329
255
 
330
256
  ## Error Handling
@@ -334,7 +260,7 @@ function processData(data) {
334
260
  **MUST handle errors and provide user feedback:**
335
261
 
336
262
  ```tsx
337
- // ✅ CORRECT - Error handling
263
+ // ✅ CORRECT: Handle errors gracefully with user feedback
338
264
  try {
339
265
  const data = await fetchData();
340
266
  setData(data);
@@ -349,24 +275,15 @@ try {
349
275
  **MUST use type-safe error handling:**
350
276
 
351
277
  ```tsx
352
- // ✅ CORRECT - Type-safe errors
278
+ // ✅ CORRECT: Type-safe error handling
353
279
  function isApiError(error: unknown): error is ApiError {
354
- return (
355
- typeof error === 'object' &&
356
- error !== null &&
357
- 'code' in error &&
358
- 'message' in error
359
- );
280
+ return typeof error === 'object' && error !== null && 'code' in error && 'message' in error;
360
281
  }
361
-
362
282
  try {
363
283
  await apiCall();
364
284
  } catch (error) {
365
- if (isApiError(error)) {
366
- handleApiError(error);
367
- } else {
368
- handleUnknownError(error);
369
- }
285
+ if (isApiError(error)) handleApiError(error);
286
+ else handleUnknownError(error);
370
287
  }
371
288
  ```
372
289