@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
@@ -14,9 +14,9 @@ import type {
14
14
  import { createLogger } from '../../../utils/core/logger';
15
15
 
16
16
  /**
17
- * Debug levels for controlling verbosity
17
+ * Debug levels for controlling verbosity (internal use only)
18
18
  */
19
- export enum DebugLevel {
19
+ enum DebugLevel {
20
20
  NONE = 0,
21
21
  ERROR = 1,
22
22
  WARN = 2,
@@ -26,9 +26,9 @@ export enum DebugLevel {
26
26
  }
27
27
 
28
28
  /**
29
- * Performance debug configuration
29
+ * Performance debug configuration (internal use only)
30
30
  */
31
- export interface DebugConfig {
31
+ interface DebugConfig {
32
32
  enabled: boolean;
33
33
  level: DebugLevel;
34
34
  logToConsole: boolean;
@@ -41,9 +41,9 @@ export interface DebugConfig {
41
41
  }
42
42
 
43
43
  /**
44
- * Default debug configuration
44
+ * Default debug configuration (internal use only)
45
45
  */
46
- export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
46
+ const DEFAULT_DEBUG_CONFIG: DebugConfig = {
47
47
  enabled: import.meta.env.MODE === 'development',
48
48
  level: DebugLevel.INFO,
49
49
  logToConsole: true,
@@ -56,9 +56,9 @@ export const DEFAULT_DEBUG_CONFIG: DebugConfig = {
56
56
  };
57
57
 
58
58
  /**
59
- * Debug log entry interface
59
+ * Debug log entry interface (internal use only)
60
60
  */
61
- export interface DebugLogEntry {
61
+ interface DebugLogEntry {
62
62
  timestamp: number;
63
63
  level: DebugLevel;
64
64
  category: string;
@@ -70,9 +70,9 @@ export interface DebugLogEntry {
70
70
  }
71
71
 
72
72
  /**
73
- * Performance timeline entry
73
+ * Performance timeline entry (internal use only)
74
74
  */
75
- export interface PerformanceTimelineEntry {
75
+ interface PerformanceTimelineEntry {
76
76
  id: string;
77
77
  operation: string;
78
78
  startTime: number;
@@ -83,9 +83,9 @@ export interface PerformanceTimelineEntry {
83
83
  }
84
84
 
85
85
  /**
86
- * Memory snapshot
86
+ * Memory snapshot (internal use only)
87
87
  */
88
- export interface MemorySnapshot {
88
+ interface MemorySnapshot {
89
89
  timestamp: number;
90
90
  heapUsed: number;
91
91
  heapTotal: number;
@@ -94,9 +94,9 @@ export interface MemorySnapshot {
94
94
  }
95
95
 
96
96
  /**
97
- * Render performance data
97
+ * Render performance data (internal use only)
98
98
  */
99
- export interface RenderPerformanceData {
99
+ interface RenderPerformanceData {
100
100
  componentName: string;
101
101
  renderCount: number;
102
102
  totalRenderTime: number;
@@ -106,9 +106,9 @@ export interface RenderPerformanceData {
106
106
  }
107
107
 
108
108
  /**
109
- * Advanced DataTable debugger
109
+ * Advanced DataTable debugger (internal use only)
110
110
  */
111
- export class DataTableDebugger {
111
+ class DataTableDebugger {
112
112
  private config: DebugConfig
113
113
  private logger = createLogger('DataTableDebugger');
114
114
  private logEntries: DebugLogEntry[] = [];
@@ -469,104 +469,9 @@ export class DataTableDebugger {
469
469
  }
470
470
 
471
471
  /**
472
- * Global debugger instance
472
+ * Global debugger instance (internal use only)
473
473
  */
474
- export const dataTableDebugger = new DataTableDebugger();
475
-
476
- /**
477
- * Performance profiler decorator
478
- */
479
- export function profile(operation: string) {
480
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
481
- return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
482
- const originalMethod = descriptor.value;
483
-
484
- descriptor.value = async function (this: unknown, ...args: unknown[]) {
485
- const operationId = `${target.constructor.name}.${propertyKey}_${Date.now()}`;
486
-
487
- dataTableDebugger.startOperation(operationId, operation, {
488
- className: target.constructor.name,
489
- methodName: propertyKey,
490
- args: args.length,
491
- });
492
-
493
- try {
494
- const result = await originalMethod.apply(this, args);
495
- dataTableDebugger.endOperation(operationId, { success: true });
496
- return result;
497
- } catch (error) {
498
- dataTableDebugger.endOperation(operationId, { success: false, error: error instanceof Error ? error.message : String(error) });
499
- dataTableDebugger.log(DebugLevel.ERROR, 'Performance', `Operation failed: ${operation}`, error);
500
- throw error;
501
- }
502
- };
503
-
504
- return descriptor;
505
- };
506
- }
507
-
508
- /**
509
- * Memory monitoring utility
510
- */
511
- export class MemoryMonitor {
512
- private debuggerInstance: DataTableDebugger;
513
- private intervalId: NodeJS.Timeout | null = null;
514
-
515
- constructor(debuggerInstance: DataTableDebugger = dataTableDebugger) {
516
- this.debuggerInstance = debuggerInstance;
517
- }
518
-
519
- start(interval: number = 5000): void {
520
- this.stop(); // Stop any existing monitoring
521
-
522
- this.intervalId = setInterval(() => {
523
- this.debuggerInstance.takeMemorySnapshot('periodic');
524
- }, interval);
525
- }
526
-
527
- stop(): void {
528
- if (this.intervalId) {
529
- clearInterval(this.intervalId);
530
- this.intervalId = null;
531
- }
532
- }
533
- }
534
-
535
- /**
536
- * Performance monitoring React hook
537
- */
538
- export function usePerformanceDebugger(componentName: string) {
539
- const startTime = React.useRef<number>(0);
540
-
541
- React.useEffect(() => {
542
- startTime.current = performance.now();
543
-
544
- return () => {
545
- const renderTime = performance.now() - startTime.current;
546
- dataTableDebugger.trackRender(componentName, renderTime);
547
- };
548
- });
549
-
550
- const trackOperation = React.useCallback((operation: string, fn: () => unknown) => {
551
- const operationId = `${componentName}_${operation}_${Date.now()}`;
552
- dataTableDebugger.startOperation(operationId, operation);
553
-
554
- try {
555
- const result = fn();
556
- dataTableDebugger.endOperation(operationId);
557
- return result;
558
- } catch (error) {
559
- dataTableDebugger.endOperation(operationId, { error: error instanceof Error ? error.message : String(error) });
560
- throw error;
561
- }
562
- }, [componentName]);
563
-
564
- return {
565
- trackOperation,
566
- log: (level: DebugLevel, message: string, data?: unknown) =>
567
- dataTableDebugger.log(level, componentName, message, data),
568
- };
569
- }
474
+ const dataTableDebugger = new DataTableDebugger();
570
475
 
571
476
  /**
572
477
  * Development tools integration
@@ -23,6 +23,10 @@ export enum DataTableErrorType {
23
23
  MEMORY = 'memory'
24
24
  }
25
25
 
26
+ /**
27
+ * Custom error class for DataTable operations.
28
+ * Provides error type and recoverability information.
29
+ */
26
30
  export class DataTableError extends Error {
27
31
  constructor(
28
32
  message: string,
@@ -34,6 +38,10 @@ export class DataTableError extends Error {
34
38
  }
35
39
  }
36
40
 
41
+ /**
42
+ * Error recovery manager for DataTable.
43
+ * Handles error recovery strategies and error logging.
44
+ */
37
45
  export class ErrorRecoveryManager {
38
46
  constructor(private config: FallbackConfig) {}
39
47
 
@@ -46,6 +54,10 @@ export class ErrorRecoveryManager {
46
54
  }
47
55
  }
48
56
 
57
+ /**
58
+ * Memory monitor for DataTable.
59
+ * Tracks memory usage and provides warnings when thresholds are exceeded.
60
+ */
49
61
  export class MemoryMonitor {
50
62
  constructor(private threshold: number = 100) {}
51
63
 
@@ -333,6 +333,15 @@ export async function exportToCSVWithTableRows(
333
333
  * - Triggers browser download
334
334
  * - Throws error if export fails
335
335
  */
336
+ /**
337
+ * Exports DataTable data to CSV format.
338
+ * Handles column mapping, data formatting, and browser download.
339
+ *
340
+ * @template TData - The type of data records in the table
341
+ * @param data - Array of data records to export
342
+ * @param columns - Column definitions for export
343
+ * @param filename - Name of the CSV file to download
344
+ */
336
345
  export function exportToCSV<TData extends DataRecord>(
337
346
  data: TData[],
338
347
  columns: ExportColumn[],
@@ -11,10 +11,18 @@
11
11
  import { createLogger } from '../../../utils/core/logger';
12
12
  import type { CellValue } from '../types';
13
13
 
14
+ /**
15
+ * Column mapping interface for CSV import.
16
+ * Maps target field names to possible CSV column names.
17
+ */
14
18
  export interface ColumnMapping {
15
19
  [targetField: string]: string[];
16
20
  }
17
21
 
22
+ /**
23
+ * Options for flexible CSV import.
24
+ * Configures column mapping, date parsing, validation, and other import settings.
25
+ */
18
26
  export interface ImportOptions {
19
27
  columnMappings?: ColumnMapping;
20
28
  dateFormats?: readonly string[];
@@ -160,6 +168,10 @@ export interface ImportError {
160
168
  message: string;
161
169
  }
162
170
 
171
+ /**
172
+ * Import warning interface.
173
+ * Represents warnings encountered during CSV import.
174
+ */
163
175
  export interface ImportWarning {
164
176
  row: number;
165
177
  field: string;
@@ -609,54 +621,6 @@ export const commonMappings = {
609
621
  }
610
622
  };
611
623
 
612
- /**
613
- * Helper function to create import options with predefined date format sets
614
- */
615
- export function createImportOptions(options: Partial<ImportOptions> = {}): ImportOptions {
616
- return {
617
- dateFormats: DATE_FORMAT_SETS.ALL,
618
- strictDateParsing: false,
619
- ...options,
620
- };
621
- }
622
-
623
- /**
624
- * Helper function to create import options for specific regions
625
- */
626
- export function createRegionalImportOptions(region: 'US' | 'EUROPEAN' | 'ISO' | 'NATURAL' | 'ALL', options: Partial<ImportOptions> = {}): ImportOptions {
627
- return {
628
- dateFormats: DATE_FORMAT_SETS[region],
629
- strictDateParsing: false,
630
- ...options,
631
- };
632
- }
633
-
634
- /**
635
- * Helper function to test if a string can be parsed as a date
636
- */
637
- export function testDateParsing(dateStr: string, formats?: string[]): { success: boolean; parsedDate?: Date; matchedFormat?: string } {
638
- if (!dateStr || typeof dateStr !== 'string') {
639
- return { success: false };
640
- }
641
-
642
- const testFormats = formats || DATE_FORMAT_SETS.ALL;
643
-
644
- for (const format of testFormats) {
645
- // This is a simplified version of the parseDateWithFormat function
646
- // In a real implementation, you'd want to reuse the actual parsing logic
647
- try {
648
- const date = new Date(dateStr);
649
- if (!isNaN(date.getTime())) {
650
- return { success: true, parsedDate: date, matchedFormat: 'native' };
651
- }
652
- } catch (error) {
653
- // Continue to next format
654
- }
655
- }
656
-
657
- return { success: false };
658
- }
659
-
660
624
  /**
661
625
  * Helper function to get suggested date formats based on sample data
662
626
  */
@@ -121,6 +121,14 @@ export interface PaginationBinding {
121
121
  * });
122
122
  * ```
123
123
  */
124
+ /**
125
+ * Creates a unified pagination binding that works across all pagination modes.
126
+ * Provides consistent pagination state and actions regardless of client/server/hybrid mode.
127
+ *
128
+ * @template TData - The type of data records in the table
129
+ * @param config - Pagination binding configuration
130
+ * @returns Unified pagination state and actions
131
+ */
124
132
  export function getPaginationBinding<TData extends DataRecord>(
125
133
  config: PaginationBindingConfig<TData>
126
134
  ): PaginationBinding {
@@ -17,7 +17,7 @@ import type {
17
17
  // ============================================================================
18
18
 
19
19
  /**
20
- * Determines the optimal pagination mode based on dataset size
20
+ * Determines the optimal pagination mode based on dataset size.
21
21
  *
22
22
  * IMPORTANT: This function NEVER returns 'server' mode - it only returns 'client' or 'hybrid'.
23
23
  * Server mode should ONLY be used when serverSide config is explicitly provided.
@@ -26,6 +26,10 @@ import type {
26
26
  *
27
27
  * For large datasets (>10k rows), returns 'hybrid' which still uses client-side pagination
28
28
  * but with optimizations. If true server-side pagination is needed, serverSide config must be provided.
29
+ *
30
+ * @param dataLength - Number of rows in the dataset
31
+ * @param serverSideThreshold - Threshold for switching to hybrid mode (default: 10000)
32
+ * @returns Optimal pagination mode ('client' or 'hybrid')
29
33
  */
30
34
  export function determinePaginationMode(
31
35
  dataLength: number,
@@ -43,10 +43,10 @@
43
43
  * </DialogHeader>
44
44
  * <DialogBody>
45
45
  * <section className="space-y-4">
46
- * <div className="grid grid-cols-4 items-center gap-4">
46
+ * <fieldset className="grid grid-cols-4 items-center gap-4">
47
47
  * <Label htmlFor="name" className="text-right">Name</Label>
48
48
  * <Input id="name" defaultValue="John Doe" className="col-span-3" />
49
- * </div>
49
+ * </fieldset>
50
50
  * </section>
51
51
  * </DialogBody>
52
52
  * <DialogFooter>
@@ -8,7 +8,8 @@ import React from 'react';
8
8
  import { screen, waitFor } from '@testing-library/react';
9
9
  import userEvent from '@testing-library/user-event';
10
10
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
11
- import { ErrorBoundary } from './ErrorBoundary';
11
+ import { ErrorBoundary } from './index';
12
+ import { ErrorBoundaryProvider } from './ErrorBoundaryContext';
12
13
  import { renderWithProviders } from '../../__tests__/helpers/test-utils';
13
14
 
14
15
  // Mock the performance budget monitor
@@ -778,4 +779,182 @@ describe('ErrorBoundary Component', () => {
778
779
  }
779
780
  vi.clearAllMocks();
780
781
  });
782
+
783
+ describe('Global Error Handler', () => {
784
+ it('uses global error handler when no onError prop is provided', async () => {
785
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
786
+ const globalErrorHandler = vi.fn();
787
+
788
+ renderWithProviders(
789
+ <ErrorBoundaryProvider defaultErrorHandler={globalErrorHandler}>
790
+ <ErrorBoundary componentName="TestComponent">
791
+ <ThrowingComponent />
792
+ </ErrorBoundary>
793
+ </ErrorBoundaryProvider>
794
+ );
795
+
796
+ await waitFor(() => {
797
+ expect(globalErrorHandler).toHaveBeenCalledTimes(1);
798
+ expect(globalErrorHandler).toHaveBeenCalledWith(
799
+ expect.any(Error),
800
+ expect.any(Object), // errorInfo
801
+ expect.any(String), // errorId
802
+ 'TestComponent' // componentName
803
+ );
804
+ }, { interval: 10 });
805
+
806
+ consoleSpy.mockRestore();
807
+ });
808
+
809
+ it('uses global error handler with default component name when componentName not provided', async () => {
810
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
811
+ const globalErrorHandler = vi.fn();
812
+
813
+ renderWithProviders(
814
+ <ErrorBoundaryProvider defaultErrorHandler={globalErrorHandler}>
815
+ <ErrorBoundary>
816
+ <ThrowingComponent />
817
+ </ErrorBoundary>
818
+ </ErrorBoundaryProvider>
819
+ );
820
+
821
+ await waitFor(() => {
822
+ expect(globalErrorHandler).toHaveBeenCalledTimes(1);
823
+ expect(globalErrorHandler).toHaveBeenCalledWith(
824
+ expect.any(Error),
825
+ expect.any(Object), // errorInfo
826
+ expect.any(String), // errorId
827
+ 'Unknown Component' // componentName (default)
828
+ );
829
+ }, { interval: 10 });
830
+
831
+ consoleSpy.mockRestore();
832
+ });
833
+
834
+ it('prefers onError prop over global error handler', async () => {
835
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
836
+ const globalErrorHandler = vi.fn();
837
+ const localErrorHandler = vi.fn();
838
+
839
+ renderWithProviders(
840
+ <ErrorBoundaryProvider defaultErrorHandler={globalErrorHandler}>
841
+ <ErrorBoundary
842
+ componentName="TestComponent"
843
+ onError={localErrorHandler}
844
+ >
845
+ <ThrowingComponent />
846
+ </ErrorBoundary>
847
+ </ErrorBoundaryProvider>
848
+ );
849
+
850
+ await waitFor(() => {
851
+ expect(localErrorHandler).toHaveBeenCalledTimes(1);
852
+ expect(globalErrorHandler).not.toHaveBeenCalled();
853
+ }, { interval: 10 });
854
+
855
+ consoleSpy.mockRestore();
856
+ });
857
+
858
+ it('does not call global handler when ErrorBoundary is not wrapped in provider', async () => {
859
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
860
+ const globalErrorHandler = vi.fn();
861
+
862
+ // Render without provider
863
+ renderWithProviders(
864
+ <ErrorBoundary componentName="TestComponent">
865
+ <ThrowingComponent />
866
+ </ErrorBoundary>
867
+ );
868
+
869
+ await waitFor(() => {
870
+ expect(screen.getByText('Error in TestComponent')).toBeInTheDocument();
871
+ }, { interval: 10 });
872
+
873
+ // Global handler should not be called since there's no provider
874
+ expect(globalErrorHandler).not.toHaveBeenCalled();
875
+
876
+ consoleSpy.mockRestore();
877
+ });
878
+
879
+ it('works with nested ErrorBoundary providers (inner provider overrides outer)', async () => {
880
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
881
+ const outerErrorHandler = vi.fn();
882
+ const innerErrorHandler = vi.fn();
883
+
884
+ renderWithProviders(
885
+ <ErrorBoundaryProvider defaultErrorHandler={outerErrorHandler}>
886
+ <ErrorBoundary componentName="Outer">
887
+ <ErrorBoundaryProvider defaultErrorHandler={innerErrorHandler}>
888
+ <ErrorBoundary componentName="Inner">
889
+ <ThrowingComponent />
890
+ </ErrorBoundary>
891
+ </ErrorBoundaryProvider>
892
+ </ErrorBoundary>
893
+ </ErrorBoundaryProvider>
894
+ );
895
+
896
+ await waitFor(() => {
897
+ expect(innerErrorHandler).toHaveBeenCalledTimes(1);
898
+ expect(innerErrorHandler).toHaveBeenCalledWith(
899
+ expect.any(Error),
900
+ expect.any(Object),
901
+ expect.any(String),
902
+ 'Inner'
903
+ );
904
+ // Outer handler should not be called for inner boundary
905
+ expect(outerErrorHandler).not.toHaveBeenCalled();
906
+ }, { interval: 10 });
907
+
908
+ consoleSpy.mockRestore();
909
+ });
910
+
911
+ it('allows ErrorBoundaryProvider without defaultErrorHandler (no-op)', async () => {
912
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
913
+
914
+ renderWithProviders(
915
+ <ErrorBoundaryProvider>
916
+ <ErrorBoundary componentName="TestComponent">
917
+ <ThrowingComponent />
918
+ </ErrorBoundary>
919
+ </ErrorBoundaryProvider>
920
+ );
921
+
922
+ await waitFor(() => {
923
+ expect(screen.getByText('Error in TestComponent')).toBeInTheDocument();
924
+ }, { interval: 10 });
925
+
926
+ // Should render error UI without calling any handler
927
+ expect(screen.getByText('Error in TestComponent')).toBeInTheDocument();
928
+
929
+ consoleSpy.mockRestore();
930
+ });
931
+
932
+ it('passes correct error information to global handler', async () => {
933
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
934
+ const globalErrorHandler = vi.fn();
935
+ const testError = new Error('Custom test error');
936
+
937
+ renderWithProviders(
938
+ <ErrorBoundaryProvider defaultErrorHandler={globalErrorHandler}>
939
+ <ErrorBoundary componentName="TestComponent">
940
+ <ThrowingComponent errorMessage="Custom test error" />
941
+ </ErrorBoundary>
942
+ </ErrorBoundaryProvider>
943
+ );
944
+
945
+ await waitFor(() => {
946
+ expect(globalErrorHandler).toHaveBeenCalledTimes(1);
947
+ const callArgs = globalErrorHandler.mock.calls[0];
948
+ expect(callArgs[0]).toBeInstanceOf(Error);
949
+ expect(callArgs[0].message).toBe('Custom test error');
950
+ expect(callArgs[1]).toBeDefined(); // errorInfo
951
+ expect(callArgs[1].componentStack).toBeDefined();
952
+ expect(typeof callArgs[2]).toBe('string'); // errorId
953
+ expect(callArgs[2]).toMatch(/^error_/); // errorId format
954
+ expect(callArgs[3]).toBe('TestComponent'); // componentName
955
+ }, { interval: 10 });
956
+
957
+ consoleSpy.mockRestore();
958
+ });
959
+ });
781
960
  });
@@ -25,10 +25,35 @@
25
25
  * <MyComponent />
26
26
  * </ErrorBoundary>
27
27
  *
28
+ * // Using global error handler (recommended for applications)
29
+ * import { ErrorBoundaryProvider, ErrorBoundary } from '@jmruthers/pace-core';
30
+ *
31
+ * // Setup once in main.tsx
32
+ * <ErrorBoundaryProvider
33
+ * defaultErrorHandler={(error, errorInfo, errorId, componentName) => {
34
+ * if (import.meta.env.DEV) {
35
+ * console.error(`[${componentName}] ErrorBoundary caught error:`, error, errorInfo);
36
+ * }
37
+ * errorTracking.captureException(error, {
38
+ * componentStack: errorInfo.componentStack,
39
+ * errorBoundary: true,
40
+ * errorId,
41
+ * componentName,
42
+ * });
43
+ * }}
44
+ * >
45
+ * <App />
46
+ * </ErrorBoundaryProvider>
47
+ *
48
+ * // Then use ErrorBoundary without onError prop - uses global handler
49
+ * <ErrorBoundary componentName="AppRoot">
50
+ * <AppContent />
51
+ * </ErrorBoundary>
52
+ *
28
53
  * // Error boundary with custom fallback
29
54
  * <ErrorBoundary
30
55
  * componentName="UserProfile"
31
- * fallback={<div>Something went wrong loading the profile.</div>}
56
+ * fallback={<section>Something went wrong loading the profile.</section>}
32
57
  * onError={(error, errorInfo, errorId) => {
33
58
  * console.log('Error caught:', errorId, error);
34
59
  * }}
@@ -58,6 +83,16 @@
58
83
  * </ErrorBoundary>
59
84
  * <Footer />
60
85
  * </ErrorBoundary>
86
+ *
87
+ * // Per-instance onError overrides global handler
88
+ * <ErrorBoundary
89
+ * componentName="SpecialCase"
90
+ * onError={(error, errorInfo, errorId) => {
91
+ * // Custom handling for this specific case - global handler won't be called
92
+ * }}
93
+ * >
94
+ * <SpecialComponent />
95
+ * </ErrorBoundary>
61
96
  * ```
62
97
  *
63
98
  * @accessibility
@@ -120,6 +155,8 @@ export interface ErrorBoundaryProps {
120
155
  enableRetry?: boolean;
121
156
  /** Whether to enable error reporting */
122
157
  enableReporting?: boolean;
158
+ /** Internal: Global error handler from context (not part of public API) */
159
+ _globalErrorHandler?: (error: Error, errorInfo: React.ErrorInfo, errorId: string, componentName: string) => void;
123
160
  }
124
161
 
125
162
  /**
@@ -162,15 +199,16 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
162
199
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
163
200
  const { componentName = 'Unknown Component', onError, enableReporting = true } = this.props;
164
201
  const errorId = this.state.errorId!;
202
+ const componentNameForHandler = componentName || 'Unknown Component';
165
203
 
166
204
  this.setState({ errorInfo });
167
205
 
168
206
  // Enhanced logging with component name and error ID
169
- logger.error('ErrorBoundary', `[${componentName}] Caught error ${errorId}:`, error, errorInfo);
207
+ logger.error('ErrorBoundary', `[${componentNameForHandler}] Caught error ${errorId}:`, error, errorInfo);
170
208
 
171
209
  // Performance monitoring - track error occurrence
172
210
  performanceBudgetMonitor.measure('ERROR_BOUNDARY_TRIGGER', 1, {
173
- componentName,
211
+ componentName: componentNameForHandler,
174
212
  errorId,
175
213
  errorMessage: error.message,
176
214
  stack: error.stack?.substring(0, 200), // Truncated stack trace
@@ -178,12 +216,14 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
178
216
 
179
217
  // Report error if enabled
180
218
  if (enableReporting) {
181
- this.reportError(errorId, componentName);
219
+ this.reportError(errorId, componentNameForHandler);
182
220
  }
183
221
 
184
- // Call custom error handler if provided
222
+ // Call error handler: prefer prop onError, fall back to global handler from props
185
223
  if (onError) {
186
224
  onError(error, errorInfo, errorId);
225
+ } else if (this.props._globalErrorHandler) {
226
+ this.props._globalErrorHandler(error, errorInfo, errorId, componentNameForHandler);
187
227
  }
188
228
  }
189
229