@jmruthers/pace-core 0.5.193 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -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
  /**
@@ -101,36 +105,34 @@ export interface InputProps
101
105
  * />
102
106
  * ```
103
107
  */
104
- const Input = React.forwardRef<HTMLInputElement, InputProps>(
105
- ({ className, variant = 'default', size = 'md', error, type, ...props }, ref) => {
106
- return (
107
- <input
108
- type={type}
109
- className={cn(
110
- // Base styles
111
- 'flex 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',
112
-
113
- // Variant styles
114
- {
115
- 'border-input': variant === 'default' && !error,
116
- 'border-destructive focus-visible:ring-destructive': variant === 'destructive' || error,
117
- },
118
-
119
- // Size styles
120
- {
121
- 'h-8 px-2 py-1 text-xs': size === 'sm',
122
- 'h-9 px-3 py-2 text-sm': size === 'md',
123
- 'h-10 px-4 py-3 text-base': size === 'lg',
124
- },
125
-
126
- className
127
- )}
128
- ref={ref}
129
- {...props}
130
- />
131
- );
132
- }
133
- );
108
+ function Input({ className, variant = 'default', size = 'md', error, type, ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
109
+ return (
110
+ <input
111
+ type={type}
112
+ className={cn(
113
+ // Base styles
114
+ 'flex 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',
115
+
116
+ // Variant styles
117
+ {
118
+ 'border-input': variant === 'default' && !error,
119
+ 'border-destructive focus-visible:ring-destructive': variant === 'destructive' || error,
120
+ },
121
+
122
+ // Size styles
123
+ {
124
+ 'h-8 px-2 py-1 text-xs': size === 'sm',
125
+ 'h-9 px-3 py-2 text-sm': size === 'md',
126
+ 'h-10 px-4 py-3 text-base': size === 'lg',
127
+ },
128
+
129
+ className
130
+ )}
131
+ ref={ref}
132
+ {...props}
133
+ />
134
+ );
135
+ }
134
136
 
135
137
  Input.displayName = 'Input';
136
138
 
@@ -138,7 +140,7 @@ Input.displayName = 'Input';
138
140
  // INPUT GROUP COMPONENT
139
141
  // ============================================================================
140
142
 
141
- export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
143
+ export interface InputGroupProps extends React.HTMLAttributes<HTMLFieldSetElement> {
142
144
  /** Child elements to be rendered in the group */
143
145
  children: React.ReactNode;
144
146
  /** Layout orientation of the input group */
@@ -167,7 +169,7 @@ export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
167
169
  * </InputGroup>
168
170
  * ```
169
171
  */
170
- export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
172
+ export const InputGroup = React.forwardRef<HTMLFieldSetElement, InputGroupProps>(
171
173
  ({ className, children, orientation = 'vertical', spacing = 'md', ...props }, ref) => {
172
174
  const spacingClasses = {
173
175
  sm: orientation === 'horizontal' ? 'space-x-2' : 'space-y-2',
@@ -176,7 +178,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
176
178
  };
177
179
 
178
180
  return (
179
- <div
181
+ <fieldset
180
182
  ref={ref}
181
183
  className={cn(
182
184
  'flex',
@@ -187,7 +189,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
187
189
  {...props}
188
190
  >
189
191
  {children}
190
- </div>
192
+ </fieldset>
191
193
  );
192
194
  }
193
195
  );
@@ -68,7 +68,7 @@
68
68
  *
69
69
  * @dependencies
70
70
  * - @radix-ui/react-label - Core label functionality
71
- * - React 18+ - Hooks and refs
71
+ * - React 19+ - Hooks and refs
72
72
  * - Tailwind CSS - Styling
73
73
  */
74
74
 
@@ -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');
@@ -52,7 +52,7 @@
52
52
  * - Efficient rendering
53
53
  *
54
54
  * @dependencies
55
- * - React 18+ - Component framework
55
+ * - React 19+ - Component framework
56
56
  * - Tailwind CSS - Styling and animations
57
57
  */
58
58
 
@@ -105,13 +105,13 @@ vi.mock('../../utils/core/cn', () => ({
105
105
  }));
106
106
 
107
107
  describe('LoginForm Component', () => {
108
- const defaultProps = {
108
+ const baseProps = {
109
109
  onSignIn: vi.fn(),
110
110
  };
111
111
 
112
112
  describe('Rendering', () => {
113
113
  it('renders with default props', () => {
114
- renderWithProviders(<LoginForm {...defaultProps} />);
114
+ renderWithProviders(<LoginForm {...baseProps} />);
115
115
 
116
116
  expect(screen.getByTestId('login-form')).toBeInTheDocument();
117
117
  expect(screen.getByTestId('card')).toBeInTheDocument();
@@ -121,7 +121,7 @@ describe('LoginForm Component', () => {
121
121
  it('renders with custom title and subtitle', () => {
122
122
  renderWithProviders(
123
123
  <LoginForm
124
- {...defaultProps}
124
+ {...baseProps}
125
125
  title="Welcome Back"
126
126
  subtitle="Please enter your credentials"
127
127
  />
@@ -134,7 +134,7 @@ describe('LoginForm Component', () => {
134
134
  it('renders with app name in title', () => {
135
135
  renderWithProviders(
136
136
  <LoginForm
137
- {...defaultProps}
137
+ {...baseProps}
138
138
  appName="My App"
139
139
  />
140
140
  );
@@ -145,7 +145,7 @@ describe('LoginForm Component', () => {
145
145
  it('renders with custom className', () => {
146
146
  renderWithProviders(
147
147
  <LoginForm
148
- {...defaultProps}
148
+ {...baseProps}
149
149
  className="custom-login-form"
150
150
  />
151
151
  );
@@ -154,7 +154,7 @@ describe('LoginForm Component', () => {
154
154
  });
155
155
 
156
156
  it('renders form inputs with correct attributes', () => {
157
- renderWithProviders(<LoginForm {...defaultProps} />);
157
+ renderWithProviders(<LoginForm {...baseProps} />);
158
158
 
159
159
  const emailInput = screen.getByLabelText('Email');
160
160
  const passwordInput = screen.getByLabelText('Password');
@@ -169,13 +169,13 @@ describe('LoginForm Component', () => {
169
169
  });
170
170
 
171
171
  it('renders submit button with correct text', () => {
172
- renderWithProviders(<LoginForm {...defaultProps} />);
172
+ renderWithProviders(<LoginForm {...baseProps} />);
173
173
 
174
174
  expect(screen.getByRole('button', { name: 'Sign In' })).toBeInTheDocument();
175
175
  });
176
176
 
177
177
  it('renders sign-up link when showSignUp is true without onSignUp', () => {
178
- renderWithProviders(<LoginForm {...defaultProps} showSignUp={true} />);
178
+ renderWithProviders(<LoginForm {...baseProps} showSignUp={true} />);
179
179
 
180
180
  expect(screen.getByText("Don't have an account?")).toBeInTheDocument();
181
181
  expect(screen.getByRole('link', { name: 'Sign up' })).toBeInTheDocument();
@@ -186,7 +186,7 @@ describe('LoginForm Component', () => {
186
186
  const onSignUp = vi.fn();
187
187
  renderWithProviders(
188
188
  <LoginForm
189
- {...defaultProps}
189
+ {...baseProps}
190
190
  showSignUp={true}
191
191
  onSignUp={onSignUp}
192
192
  />
@@ -199,7 +199,7 @@ describe('LoginForm Component', () => {
199
199
 
200
200
  describe('Form Validation', () => {
201
201
  it('disables submit button when form is empty', () => {
202
- renderWithProviders(<LoginForm {...defaultProps} />);
202
+ renderWithProviders(<LoginForm {...baseProps} />);
203
203
 
204
204
  const submitButton = screen.getByRole('button', { name: 'Sign In' });
205
205
  expect(submitButton).toBeDisabled();
@@ -207,7 +207,7 @@ describe('LoginForm Component', () => {
207
207
 
208
208
  it('enables submit button when both fields have values', async () => {
209
209
  const user = userEvent.setup();
210
- renderWithProviders(<LoginForm {...defaultProps} />);
210
+ renderWithProviders(<LoginForm {...baseProps} />);
211
211
 
212
212
  const emailInput = screen.getByLabelText('Email');
213
213
  const passwordInput = screen.getByLabelText('Password');
@@ -224,7 +224,7 @@ describe('LoginForm Component', () => {
224
224
 
225
225
  it('disables submit button when only email is filled', async () => {
226
226
  const user = userEvent.setup();
227
- renderWithProviders(<LoginForm {...defaultProps} />);
227
+ renderWithProviders(<LoginForm {...baseProps} />);
228
228
 
229
229
  const emailInput = screen.getByLabelText('Email');
230
230
  const submitButton = screen.getByRole('button', { name: 'Sign In' });
@@ -235,7 +235,7 @@ describe('LoginForm Component', () => {
235
235
 
236
236
  it('disables submit button when only password is filled', async () => {
237
237
  const user = userEvent.setup();
238
- renderWithProviders(<LoginForm {...defaultProps} />);
238
+ renderWithProviders(<LoginForm {...baseProps} />);
239
239
 
240
240
  const passwordInput = screen.getByLabelText('Password');
241
241
  const submitButton = screen.getByRole('button', { name: 'Sign In' });
@@ -248,7 +248,7 @@ describe('LoginForm Component', () => {
248
248
  describe('User Interactions', () => {
249
249
  it('updates email input value when typed', async () => {
250
250
  const user = userEvent.setup();
251
- renderWithProviders(<LoginForm {...defaultProps} />);
251
+ renderWithProviders(<LoginForm {...baseProps} />);
252
252
 
253
253
  const emailInput = screen.getByLabelText('Email');
254
254
  await user.type(emailInput, 'test@example.com');
@@ -258,7 +258,7 @@ describe('LoginForm Component', () => {
258
258
 
259
259
  it('updates password input value when typed', async () => {
260
260
  const user = userEvent.setup();
261
- renderWithProviders(<LoginForm {...defaultProps} />);
261
+ renderWithProviders(<LoginForm {...baseProps} />);
262
262
 
263
263
  const passwordInput = screen.getByLabelText('Password');
264
264
  await user.type(passwordInput, 'password123');
@@ -269,7 +269,7 @@ describe('LoginForm Component', () => {
269
269
  it('calls onSignIn with form data when submitted', async () => {
270
270
  const user = userEvent.setup();
271
271
  const onSignIn = vi.fn().mockResolvedValue(undefined);
272
- renderWithProviders(<LoginForm {...defaultProps} onSignIn={onSignIn} />);
272
+ renderWithProviders(<LoginForm {...baseProps} onSignIn={onSignIn} />);
273
273
 
274
274
  const emailInput = screen.getByLabelText('Email');
275
275
  const passwordInput = screen.getByLabelText('Password');
@@ -290,7 +290,7 @@ describe('LoginForm Component', () => {
290
290
  const onSignUp = vi.fn();
291
291
  renderWithProviders(
292
292
  <LoginForm
293
- {...defaultProps}
293
+ {...baseProps}
294
294
  showSignUp={true}
295
295
  onSignUp={onSignUp}
296
296
  />
@@ -305,7 +305,7 @@ describe('LoginForm Component', () => {
305
305
  it('prevents form submission when form is invalid', async () => {
306
306
  const user = userEvent.setup();
307
307
  const onSignIn = vi.fn();
308
- renderWithProviders(<LoginForm {...defaultProps} onSignIn={onSignIn} />);
308
+ renderWithProviders(<LoginForm {...baseProps} onSignIn={onSignIn} />);
309
309
 
310
310
  const submitButton = screen.getByRole('button', { name: 'Sign In' });
311
311
  await user.click(submitButton);
@@ -318,7 +318,7 @@ describe('LoginForm Component', () => {
318
318
  const onSignIn = vi.fn();
319
319
  renderWithProviders(
320
320
  <LoginForm
321
- {...defaultProps}
321
+ {...baseProps}
322
322
  onSignIn={onSignIn}
323
323
  isLoading={true}
324
324
  />
@@ -338,13 +338,13 @@ describe('LoginForm Component', () => {
338
338
 
339
339
  describe('Loading States', () => {
340
340
  it('shows loading text on submit button when loading', () => {
341
- renderWithProviders(<LoginForm {...defaultProps} isLoading={true} />);
341
+ renderWithProviders(<LoginForm {...baseProps} isLoading={true} />);
342
342
 
343
343
  expect(screen.getByRole('button', { name: 'Signing in...' })).toBeInTheDocument();
344
344
  });
345
345
 
346
346
  it('disables form inputs when loading', () => {
347
- renderWithProviders(<LoginForm {...defaultProps} isLoading={true} />);
347
+ renderWithProviders(<LoginForm {...baseProps} isLoading={true} />);
348
348
 
349
349
  const emailInput = screen.getByLabelText('Email');
350
350
  const passwordInput = screen.getByLabelText('Password');
@@ -354,7 +354,7 @@ describe('LoginForm Component', () => {
354
354
  });
355
355
 
356
356
  it('disables submit button when loading', () => {
357
- renderWithProviders(<LoginForm {...defaultProps} isLoading={true} />);
357
+ renderWithProviders(<LoginForm {...baseProps} isLoading={true} />);
358
358
 
359
359
  const submitButton = screen.getByRole('button', { name: 'Signing in...' });
360
360
  expect(submitButton).toBeDisabled();
@@ -363,7 +363,7 @@ describe('LoginForm Component', () => {
363
363
 
364
364
  describe('Error Handling', () => {
365
365
  it('displays error message when provided', () => {
366
- renderWithProviders(<LoginForm {...defaultProps} />);
366
+ renderWithProviders(<LoginForm {...baseProps} />);
367
367
 
368
368
  // Simulate error state by triggering form submission with error
369
369
  const form = screen.getByTestId('login-form');
@@ -381,7 +381,7 @@ describe('LoginForm Component', () => {
381
381
 
382
382
  renderWithProviders(
383
383
  <LoginForm
384
- {...defaultProps}
384
+ {...baseProps}
385
385
  onSignIn={onSignIn}
386
386
  onError={onError}
387
387
  />
@@ -406,7 +406,7 @@ describe('LoginForm Component', () => {
406
406
 
407
407
  renderWithProviders(
408
408
  <LoginForm
409
- {...defaultProps}
409
+ {...baseProps}
410
410
  onSignIn={onSignIn}
411
411
  />
412
412
  );
@@ -431,7 +431,7 @@ describe('LoginForm Component', () => {
431
431
 
432
432
  renderWithProviders(
433
433
  <LoginForm
434
- {...defaultProps}
434
+ {...baseProps}
435
435
  onSignIn={onSignIn}
436
436
  onError={onError}
437
437
  />
@@ -459,7 +459,7 @@ describe('LoginForm Component', () => {
459
459
 
460
460
  renderWithProviders(
461
461
  <LoginForm
462
- {...defaultProps}
462
+ {...baseProps}
463
463
  onSignIn={onSignIn}
464
464
  />
465
465
  );
@@ -493,7 +493,7 @@ describe('LoginForm Component', () => {
493
493
 
494
494
  renderWithProviders(
495
495
  <LoginForm
496
- {...defaultProps}
496
+ {...baseProps}
497
497
  onSignIn={onSignIn}
498
498
  onSuccess={onSuccess}
499
499
  />
@@ -518,7 +518,7 @@ describe('LoginForm Component', () => {
518
518
 
519
519
  renderWithProviders(
520
520
  <LoginForm
521
- {...defaultProps}
521
+ {...baseProps}
522
522
  onSignIn={onSignIn}
523
523
  />
524
524
  );
@@ -540,7 +540,7 @@ describe('LoginForm Component', () => {
540
540
 
541
541
  describe('Accessibility', () => {
542
542
  it('has proper form structure', () => {
543
- renderWithProviders(<LoginForm {...defaultProps} />);
543
+ renderWithProviders(<LoginForm {...baseProps} />);
544
544
 
545
545
  const form = screen.getByTestId('login-form');
546
546
  expect(form).toBeInTheDocument();
@@ -548,7 +548,7 @@ describe('LoginForm Component', () => {
548
548
  });
549
549
 
550
550
  it('has proper label associations', () => {
551
- renderWithProviders(<LoginForm {...defaultProps} />);
551
+ renderWithProviders(<LoginForm {...baseProps} />);
552
552
 
553
553
  const emailInput = screen.getByLabelText('Email');
554
554
  const passwordInput = screen.getByLabelText('Password');
@@ -558,7 +558,7 @@ describe('LoginForm Component', () => {
558
558
  });
559
559
 
560
560
  it('has proper heading structure', () => {
561
- renderWithProviders(<LoginForm {...defaultProps} />);
561
+ renderWithProviders(<LoginForm {...baseProps} />);
562
562
 
563
563
  const title = screen.getByRole('heading', { level: 2 });
564
564
  expect(title).toBeInTheDocument();
@@ -571,7 +571,7 @@ describe('LoginForm Component', () => {
571
571
 
572
572
  renderWithProviders(
573
573
  <LoginForm
574
- {...defaultProps}
574
+ {...baseProps}
575
575
  onSignIn={onSignIn}
576
576
  />
577
577
  );
@@ -594,7 +594,7 @@ describe('LoginForm Component', () => {
594
594
 
595
595
  it('supports keyboard navigation', async () => {
596
596
  const user = userEvent.setup();
597
- renderWithProviders(<LoginForm {...defaultProps} />);
597
+ renderWithProviders(<LoginForm {...baseProps} />);
598
598
 
599
599
  const emailInput = screen.getByLabelText('Email');
600
600
  const passwordInput = screen.getByLabelText('Password');
@@ -627,7 +627,7 @@ describe('LoginForm Component', () => {
627
627
  describe('Edge Cases', () => {
628
628
  it('handles empty string values', async () => {
629
629
  const user = userEvent.setup();
630
- renderWithProviders(<LoginForm {...defaultProps} />);
630
+ renderWithProviders(<LoginForm {...baseProps} />);
631
631
 
632
632
  const emailInput = screen.getByLabelText('Email');
633
633
  const passwordInput = screen.getByLabelText('Password');
@@ -646,7 +646,7 @@ describe('LoginForm Component', () => {
646
646
  const longEmail = 'a'.repeat(100) + '@example.com';
647
647
  const longPassword = 'p'.repeat(100);
648
648
 
649
- renderWithProviders(<LoginForm {...defaultProps} />);
649
+ renderWithProviders(<LoginForm {...baseProps} />);
650
650
 
651
651
  const emailInput = screen.getByLabelText('Email');
652
652
  const passwordInput = screen.getByLabelText('Password');
@@ -663,7 +663,7 @@ describe('LoginForm Component', () => {
663
663
  const specialEmail = 'test+tag@example.co.uk';
664
664
  const specialPassword = 'P@ssw0rd!@#$%^&*()';
665
665
 
666
- renderWithProviders(<LoginForm {...defaultProps} />);
666
+ renderWithProviders(<LoginForm {...baseProps} />);
667
667
 
668
668
  const emailInput = screen.getByLabelText('Email');
669
669
  const passwordInput = screen.getByLabelText('Password');
@@ -683,7 +683,7 @@ describe('LoginForm Component', () => {
683
683
 
684
684
  renderWithProviders(
685
685
  <LoginForm
686
- {...defaultProps}
686
+ {...baseProps}
687
687
  onSignIn={onSignIn}
688
688
  />
689
689
  );
@@ -732,12 +732,12 @@ describe('LoginForm Component', () => {
732
732
 
733
733
  it('handles prop changes efficiently', () => {
734
734
  const { rerender } = renderWithProviders(
735
- <LoginForm {...defaultProps} appName="App 1" />
735
+ <LoginForm {...baseProps} appName="App 1" />
736
736
  );
737
737
 
738
738
  expect(screen.getByText('Sign in to App 1')).toBeInTheDocument();
739
739
 
740
- rerender(<LoginForm {...defaultProps} appName="App 2" />);
740
+ rerender(<LoginForm {...baseProps} appName="App 2" />);
741
741
 
742
742
  expect(screen.getByText('Sign in to App 2')).toBeInTheDocument();
743
743
  });
@@ -751,7 +751,7 @@ describe('LoginForm Component', () => {
751
751
 
752
752
  renderWithProviders(
753
753
  <LoginForm
754
- {...defaultProps}
754
+ {...baseProps}
755
755
  onSignIn={onSignIn}
756
756
  onSuccess={onSuccess}
757
757
  />
@@ -790,7 +790,7 @@ describe('LoginForm Component', () => {
790
790
 
791
791
  renderWithProviders(
792
792
  <LoginForm
793
- {...defaultProps}
793
+ {...baseProps}
794
794
  onSignIn={onSignIn}
795
795
  onError={onError}
796
796
  />
@@ -89,7 +89,7 @@
89
89
  * - Minimal re-renders
90
90
  *
91
91
  * @dependencies
92
- * - React 18+ - Hooks and memo
92
+ * - React 19+ - Hooks and memo
93
93
  * - Button component
94
94
  * - Input component
95
95
  * - Label component
@@ -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>;
@@ -167,14 +171,14 @@ export const LoginForm = React.memo<LoginFormProps>(({
167
171
  return formData.email.length > 0 && formData.password.length > 0;
168
172
  }, [formData.email, formData.password]);
169
173
 
170
- // Memoized handlers
171
- const handleEmailChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
174
+ // React Compiler handles memoization automatically
175
+ const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
172
176
  setFormData(prev => ({ ...prev, email: e.target.value }));
173
- }, []);
177
+ };
174
178
 
175
- const handlePasswordChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
179
+ const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
176
180
  setFormData(prev => ({ ...prev, password: e.target.value }));
177
- }, []);
181
+ };
178
182
 
179
183
  const handleSubmit = useCallback(async (e: React.FormEvent) => {
180
184
  e.preventDefault();
@@ -190,9 +194,9 @@ export const LoginForm = React.memo<LoginFormProps>(({
190
194
  }
191
195
  }, [formData, isFormValid, isLoading, onSignIn, onSuccess, onError]);
192
196
 
193
- const handleSignUpClick = useCallback(() => {
197
+ const handleSignUpClick = () => {
194
198
  onSignUp?.();
195
- }, [onSignUp]);
199
+ };
196
200
 
197
201
  const displayTitle = useMemo(() => title || (appName ? `Sign in to ${appName}` : 'Sign In'), [title, appName]);
198
202
  const displaySubtitle = useMemo(() => subtitle || 'Enter your credentials to continue.', [subtitle]);