@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
package/dist/hooks.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export { u as useToast } from './useToast-AyaT-x7p.js';
2
- import { a as StorageUploadOptions, c as StorageUploadResult, e as StorageListOptions, f as StorageListResult, m as StorageFileInfo } from './usePublicRouteParams-BJAlWfuJ.js';
3
- export { O as OrganisationSecurityHook, K as UseAppConfigReturn, U as UseFormDialogOptions, h as UseFormDialogReturn, J as UseOrganisationPermissionsReturn, H as UsePublicEventLogoOptions, G as UsePublicEventLogoReturn, C as UsePublicEventOptions, B as UsePublicEventReturn, E as UsePublicFileDisplayOptions, D as UsePublicFileDisplayReturn, I as UsePublicRouteParamsReturn, o as clearPublicEventCache, r as clearPublicFileDisplayCache, v as clearPublicLogoCache, A as extractEventCodeFromPath, z as generatePublicRoutePath, p as getPublicEventCacheStats, s as getPublicFileDisplayCacheStats, w as getPublicLogoCacheStats, k as useAppConfig, l as useEventTheme, g as useFormDialog, i as useOrganisationPermissions, j as useOrganisationSecurity, n as usePublicEvent, y as usePublicEventCode, t as usePublicEventLogo, q as usePublicFileDisplay, x as usePublicRouteParams, u as useZodForm } from './usePublicRouteParams-BJAlWfuJ.js';
2
+ import { S as StorageUploadOptions, a as StorageUploadResult, b as StorageListOptions, c as StorageListResult, d as StorageFileInfo } from './usePublicRouteParams-1oMokgLF.js';
3
+ export { O as OrganisationSecurityHook, l as UseAppConfigReturn, i as UseFormDialogOptions, j as UseFormDialogReturn, U as UseOrganisationPermissionsReturn, F as UsePublicEventLogoOptions, E as UsePublicEventLogoReturn, B as UsePublicEventOptions, A as UsePublicEventReturn, D as UsePublicFileDisplayOptions, C as UsePublicFileDisplayReturn, G as UsePublicRouteParamsReturn, n as clearPublicEventCache, q as clearPublicFileDisplayCache, t as clearPublicLogoCache, z as extractEventCodeFromPath, y as generatePublicRoutePath, o as getPublicEventCacheStats, r as getPublicFileDisplayCacheStats, v as getPublicLogoCacheStats, k as useAppConfig, u as useEventTheme, h as useFormDialog, e as useOrganisationPermissions, f as useOrganisationSecurity, m as usePublicEvent, x as usePublicEventCode, s as usePublicEventLogo, p as usePublicFileDisplay, w as usePublicRouteParams, g as useZodForm } from './usePublicRouteParams-1oMokgLF.js';
4
4
  import * as React$1 from 'react';
5
5
  import { SortingState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table';
6
- import { d as DataRecord, g as PerformanceConfig, S as ServerSideConfig, C as ChunkingConfig, i as SearchIndexConfig, h as PaginationMode, k as ServerSideParams, l as ServerSideResponse, A as AutocompleteOptions, m as GooglePlaceAutocompletePrediction, P as ParsedAddress } from './types-CEpcvwwF.js';
6
+ import { d as DataRecord, g as PerformanceConfig, S as ServerSideConfig, C as ChunkingConfig, i as SearchIndexConfig, h as PaginationMode, k as ServerSideParams, l as ServerSideResponse, A as AutocompleteOptions, m as GooglePlaceAutocompletePrediction, P as ParsedAddress } from './types-CkbwOr4Y.js';
7
7
  export { u as useComponentPerformance } from './useComponentPerformance-DE9l5RkL.js';
8
8
  import { SupabaseClient } from '@supabase/supabase-js';
9
9
  import { D as Database } from './database.generated-CzIvgcPu.js';
@@ -31,6 +31,10 @@ declare enum DataTableErrorType {
31
31
  SERVER_FETCH = "server_fetch",
32
32
  MEMORY = "memory"
33
33
  }
34
+ /**
35
+ * Custom error class for DataTable operations.
36
+ * Provides error type and recoverability information.
37
+ */
34
38
  declare class DataTableError extends Error {
35
39
  type: DataTableErrorType;
36
40
  recoverable: boolean;
@@ -82,6 +86,9 @@ interface UseDataTablePerformanceReturn<TData extends DataRecord> {
82
86
  */
83
87
  declare function useDataTablePerformance<TData extends DataRecord>({ data, performance, serverSide, chunking, searchIndex, fallbackConfig, onError, enableErrorRecovery }: UseDataTablePerformanceOptions<TData>): UseDataTablePerformanceReturn<TData>;
84
88
 
89
+ /**
90
+ * Options for the useFocusManagement hook.
91
+ */
85
92
  interface FocusManagementOptions {
86
93
  trapFocus?: boolean;
87
94
  autoFocus?: boolean;
@@ -90,6 +97,10 @@ interface FocusManagementOptions {
90
97
  onFocusFirst?: () => void;
91
98
  onFocusLast?: () => void;
92
99
  }
100
+ /**
101
+ * Return value of the useFocusManagement hook.
102
+ * Provides focus management utilities for accessible components.
103
+ */
93
104
  interface FocusManagementReturn {
94
105
  containerRef: React.RefObject<HTMLDivElement | null>;
95
106
  focusRef: React.RefObject<HTMLElement | null>;
@@ -101,8 +112,18 @@ interface FocusManagementReturn {
101
112
  getFocusableElements: () => HTMLElement[];
102
113
  handleEscape: (callback: () => void) => () => void;
103
114
  }
115
+ /**
116
+ * Hook for managing focus in accessible components.
117
+ * Provides focus trapping, restoration, and navigation utilities.
118
+ *
119
+ * @param options - Focus management configuration
120
+ * @returns Focus management utilities and refs
121
+ */
104
122
  declare function useFocusManagement(options?: FocusManagementOptions): FocusManagementReturn;
105
123
 
124
+ /**
125
+ * Options for the useFocusTrap hook.
126
+ */
106
127
  interface FocusTrapOptions {
107
128
  /** Whether the focus trap is active */
108
129
  isActive?: boolean;
@@ -131,6 +152,10 @@ interface FocusTrapReturn {
131
152
  */
132
153
  declare function useFocusTrap(options?: FocusTrapOptions): FocusTrapReturn;
133
154
 
155
+ /**
156
+ * Keyboard shortcut definition.
157
+ * Defines a key combination and its handler function.
158
+ */
134
159
  interface KeyboardShortcut {
135
160
  /** Key combination (e.g., 'Escape', 'Enter', 'ArrowDown', 'ctrl+s') */
136
161
  key: string;
@@ -190,6 +215,15 @@ declare function useKeyboardShortcuts(shortcuts: KeyboardShortcut[], options?: K
190
215
  */
191
216
  declare function useIsMobile(): boolean;
192
217
 
218
+ /**
219
+ * Hook for debouncing a value.
220
+ * Returns a debounced version of the value that only updates after the specified delay.
221
+ *
222
+ * @template T - The type of the value to debounce
223
+ * @param value - The value to debounce
224
+ * @param delay - The delay in milliseconds
225
+ * @returns The debounced value
226
+ */
193
227
  declare function useDebounce<T>(value: T, delay: number): T;
194
228
 
195
229
  interface UseDataTableStateOptions {
@@ -286,113 +320,9 @@ interface UseAddressAutocompleteReturn {
286
320
  declare function useAddressAutocomplete(apiKey: string, inputValue: string, options?: UseAddressAutocompleteOptions): UseAddressAutocompleteReturn;
287
321
 
288
322
  /**
289
- * @file useSecureDataAccess Hook
290
- * @package @jmruthers/pace-core
291
- * @module Hooks/useSecureDataAccess
292
- * @since 0.4.0
293
- *
294
- * Hook for secure database operations with mandatory organisation context.
295
- * Ensures all data access is properly scoped to the user's current organisation.
296
- *
297
- * @example
298
- * ```tsx
299
- * function DataComponent() {
300
- * const { secureQuery, secureInsert, secureUpdate, secureDelete } = useSecureDataAccess();
301
- *
302
- * const loadData = async () => {
303
- * try {
304
- * // Automatically includes organisation_id filter
305
- * const events = await secureQuery('core_events', '*', { is_visible: true });
306
- * console.log('Organisation events:', events);
307
- * } catch (error) {
308
- * console.error('Failed to load data:', error);
309
- * }
310
- * };
311
- *
312
- * const createEvent = async (eventData) => {
313
- * try {
314
- * // Automatically sets organisation_id
315
- * const newEvent = await secureInsert('core_events', eventData);
316
- * console.log('Created event:', newEvent);
317
- * } catch (error) {
318
- * console.error('Failed to create event:', error);
319
- * }
320
- * };
321
- *
322
- * return (
323
- * <div>
324
- * <button onClick={loadData}>Load Data</button>
325
- * <button onClick={() => createEvent({ event_name: 'New Event' })}>
326
- * Create Event
327
- * </button>
328
- * </div>
329
- * );
330
- * }
331
- * ```
332
- *
333
- * @security
334
- * - All queries automatically include organisation_id filter
335
- * - Validates organisation context before any operation
336
- * - Prevents data leaks between organisations
337
- * - Error handling for security violations
338
- * - Type-safe database operations
339
- */
340
- interface SecureDataAccessReturn {
341
- /** Execute a secure query with organisation filtering */
342
- secureQuery: <T = any>(table: string, columns: string, filters?: Record<string, any>, options?: {
343
- orderBy?: string;
344
- ascending?: boolean;
345
- limit?: number;
346
- offset?: number;
347
- }) => Promise<T[]>;
348
- /** Execute a secure insert with organisation context */
349
- secureInsert: <T = any>(table: string, data: Record<string, any>) => Promise<T>;
350
- /** Execute a secure update with organisation filtering */
351
- secureUpdate: <T = any>(table: string, data: Record<string, any>, filters: Record<string, any>) => Promise<T[]>;
352
- /** Execute a secure delete with organisation filtering */
353
- secureDelete: (table: string, filters: Record<string, any>) => Promise<void>;
354
- /** Execute a secure RPC call with organisation context */
355
- secureRpc: <T = any>(functionName: string, params?: Record<string, any>) => Promise<T>;
356
- /** Get current organisation ID */
357
- getCurrentOrganisationId: () => string;
358
- /** Validate organisation context */
359
- validateContext: () => void;
360
- /** Check if data access is allowed for a table and operation */
361
- isDataAccessAllowed: (table: string, operation: string) => boolean;
362
- /** Get all data access permissions for current user */
363
- getDataAccessPermissions: () => Record<string, string[]>;
364
- /** Check if strict mode is enabled */
365
- isStrictMode: boolean;
366
- /** Check if audit logging is enabled */
367
- isAuditLogEnabled: boolean;
368
- /** Get data access history */
369
- getDataAccessHistory: () => DataAccessRecord[];
370
- /** Clear data access history */
371
- clearDataAccessHistory: () => void;
372
- /** Validate data access attempt */
373
- validateDataAccess: (table: string, operation: string) => boolean;
374
- }
375
- interface DataAccessRecord {
376
- table: string;
377
- operation: string;
378
- userId: string;
379
- organisationId: string;
380
- allowed: boolean;
381
- timestamp: string;
382
- query?: string;
383
- filters?: Record<string, any>;
384
- }
385
- /**
386
- * Hook for secure data access with automatic organisation filtering
387
- *
388
- * All database operations automatically include organisation context:
389
- * - Queries filter by organisation_id
390
- * - Inserts include organisation_id
391
- * - Updates/deletes are scoped to organisation
392
- * - RPC calls include organisation_id parameter
323
+ * Performance metrics interface.
324
+ * Represents performance measurement data for components or operations.
393
325
  */
394
- declare function useSecureDataAccess(): SecureDataAccessReturn;
395
-
396
326
  interface PerformanceMetrics {
397
327
  renderTime: number;
398
328
  componentName: string;
@@ -480,25 +410,20 @@ interface UseQueryCacheReturn {
480
410
  * );
481
411
  * ```
482
412
  */
413
+ /**
414
+ * Hook for in-memory query result caching.
415
+ * Provides caching for frequently accessed data to eliminate duplicate queries.
416
+ *
417
+ * @param supabase - Optional Supabase client instance
418
+ * @returns Query cache utilities including get, invalidate, and clear functions
419
+ */
483
420
  declare function useQueryCache(supabase?: SupabaseClient<Database>): UseQueryCacheReturn;
484
421
  /**
485
422
  * Pre-configured cache helpers for common queries
486
423
  */
487
424
  declare const queryCacheHelpers: {
488
- /**
489
- * Cache core_person queries by user_id
490
- * TTL: 5 minutes
491
- */
492
425
  pacePersonByUserId: <T>(supabase: SupabaseClient<Database>, userId: string, fetchFn: () => Promise<T>) => Promise<T>;
493
- /**
494
- * Cache core_member queries by person_id
495
- * TTL: 5 minutes
496
- */
497
426
  paceMemberByPersonId: <T>(supabase: SupabaseClient<Database>, personId: string, fetchFn: () => Promise<T>) => Promise<T>;
498
- /**
499
- * Cache rbac_app_pages queries by app_id
500
- * TTL: 15 minutes (app pages are relatively static)
501
- */
502
427
  rbacAppPagesByAppId: <T>(supabase: SupabaseClient<Database>, appId: string, fetchFn: () => Promise<T>) => Promise<T>;
503
428
  };
504
429
 
@@ -538,6 +463,10 @@ declare const queryCacheHelpers: {
538
463
  * ```
539
464
  */
540
465
 
466
+ /**
467
+ * Return value of the useFileDisplay hook.
468
+ * Provides file URLs, references, loading state, error, and refetch function.
469
+ */
541
470
  interface UseFileDisplayReturn {
542
471
  /** Single file URL if category is provided and file found, null otherwise */
543
472
  fileUrl: string | null;
@@ -688,6 +617,10 @@ interface UseStorageOptions {
688
617
  appName: string;
689
618
  orgId: string;
690
619
  }
620
+ /**
621
+ * Return value of the useStorage hook.
622
+ * Provides storage operations including upload, URL generation, file management, and listing.
623
+ */
691
624
  interface UseStorageReturn {
692
625
  uploadFile: (file: File, options?: Partial<StorageUploadOptions>) => Promise<StorageUploadResult>;
693
626
  isUploading: boolean;
@@ -769,4 +702,4 @@ interface UsePreventTabReloadOptions {
769
702
  */
770
703
  declare function usePreventTabReload(options?: UsePreventTabReloadOptions): void;
771
704
 
772
- export { type SecureDataAccessReturn, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseDataTablePerformanceOptions, type UseDataTablePerformanceReturn, type UseFileDisplayOptions, type UseFileDisplayReturn, type UseFileUrlCacheReturn, type UsePreventTabReloadOptions, type UseQueryCacheOptions, type UseQueryCacheReturn, type UseStorageOptions, type UseStorageReturn, cleanupQueryCache, clearFileDisplayCache, getFileDisplayCacheStats, invalidateFileDisplayCache, queryCacheHelpers, useAddressAutocomplete, useDataTablePerformance, useDataTableState, useDebounce, useFileDisplay, useFileUpload, useFileUrlCache, useFocusManagement, useFocusTrap, useIsMobile, useKeyboardShortcuts, usePerformanceMonitor, usePreventTabReload, useQueryCache, useSecureDataAccess, useStorage };
705
+ export { type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseDataTablePerformanceOptions, type UseDataTablePerformanceReturn, type UseFileDisplayOptions, type UseFileDisplayReturn, type UseFileUrlCacheReturn, type UsePreventTabReloadOptions, type UseQueryCacheOptions, type UseQueryCacheReturn, type UseStorageOptions, type UseStorageReturn, cleanupQueryCache, clearFileDisplayCache, getFileDisplayCacheStats, invalidateFileDisplayCache, queryCacheHelpers, useAddressAutocomplete, useDataTablePerformance, useDataTableState, useDebounce, useFileDisplay, useFileUpload, useFileUrlCache, useFocusManagement, useFocusTrap, useIsMobile, useKeyboardShortcuts, usePerformanceMonitor, usePreventTabReload, useQueryCache, useStorage };
package/dist/hooks.js CHANGED
@@ -12,10 +12,7 @@ import {
12
12
  usePublicEventLogo,
13
13
  usePublicRouteParams,
14
14
  useZodForm
15
- } from "./chunk-4N5C5XZU.js";
16
- import {
17
- useSecureDataAccess
18
- } from "./chunk-EXUD6RNJ.js";
15
+ } from "./chunk-2UOI2FG5.js";
19
16
  import {
20
17
  archiveFile,
21
18
  cleanupQueryCache,
@@ -37,18 +34,18 @@ import {
37
34
  usePreventTabReload,
38
35
  usePublicFileDisplay,
39
36
  useQueryCache
40
- } from "./chunk-JBKQ3SAO.js";
37
+ } from "./chunk-SFZUDBL5.js";
41
38
  import {
42
39
  useDataTablePerformance,
43
40
  useToast
44
- } from "./chunk-3QRJFVBR.js";
41
+ } from "./chunk-6SOIHG6Z.js";
45
42
  import {
46
43
  useAppConfig,
47
44
  useOrganisationSecurity
48
- } from "./chunk-3XTALGJF.js";
45
+ } from "./chunk-MMZ7JXPU.js";
49
46
  import "./chunk-KQCRWDSA.js";
50
- import "./chunk-BYFSK72L.js";
51
- import "./chunk-KNC55RTG.js";
47
+ import "./chunk-EHMR7VYL.js";
48
+ import "./chunk-24UVZUZG.js";
52
49
  import "./chunk-63FOKYGO.js";
53
50
  import "./chunk-ZSAAAMVR.js";
54
51
  import "./chunk-QXHPKYJV.js";
@@ -59,9 +56,9 @@ import "./chunk-G37KK66H.js";
59
56
  import {
60
57
  PERFORMANCE_BUDGETS,
61
58
  performanceBudgetMonitor
62
- } from "./chunk-I7PSE6JW.js";
59
+ } from "./chunk-FMUCXFII.js";
63
60
  import "./chunk-VBXEHIUJ.js";
64
- import "./chunk-SQGMNID3.js";
61
+ import "./chunk-L4OXEN46.js";
65
62
  import {
66
63
  createLogger
67
64
  } from "./chunk-PWLANIRT.js";
@@ -782,7 +779,6 @@ export {
782
779
  usePublicFileDisplay,
783
780
  usePublicRouteParams,
784
781
  useQueryCache,
785
- useSecureDataAccess,
786
782
  useStorage,
787
783
  useToast,
788
784
  useZodForm
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useFocusManagement.ts","../src/hooks/useFocusTrap.ts","../src/hooks/useKeyboardShortcuts.ts","../src/hooks/useIsMobile.ts","../src/hooks/useDataTableState.ts","../src/hooks/usePerformanceMonitor.ts","../src/hooks/useFileUrlCache.ts","../src/hooks/useStorage.ts"],"sourcesContent":["\nimport { useRef, useCallback, useEffect } from 'react';\n\nexport interface FocusManagementOptions {\n trapFocus?: boolean;\n autoFocus?: boolean;\n restoreFocus?: boolean;\n onEscape?: () => void;\n onFocusFirst?: () => void;\n onFocusLast?: () => void;\n}\n\nexport interface FocusManagementReturn {\n containerRef: React.RefObject<HTMLDivElement | null>;\n focusRef: React.RefObject<HTMLElement | null>;\n setFocus: (element: HTMLElement | null) => void;\n focusFirst: () => void;\n focusLast: () => void;\n trapFocus: () => void;\n releaseFocus: () => void;\n getFocusableElements: () => HTMLElement[];\n handleEscape: (callback: () => void) => () => void;\n}\n\nexport function useFocusManagement(options: FocusManagementOptions = {}): FocusManagementReturn {\n const { \n trapFocus = false, \n autoFocus = false, \n restoreFocus = false,\n onEscape,\n onFocusFirst,\n onFocusLast \n } = options;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const focusRef = useRef<HTMLElement | null>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const trapFocusActiveRef = useRef<boolean>(false);\n\n const setFocus = useCallback((element: HTMLElement | null) => {\n focusRef.current = element;\n element?.focus();\n }, []);\n\n const getFocusableElements = useCallback((): HTMLElement[] => {\n if (!containerRef.current) return [];\n\n return Array.from(\n containerRef.current.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute('disabled') && !el.hasAttribute('hidden'));\n }, []);\n\n const focusFirst = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[0]);\n onFocusFirst?.();\n }\n }, [getFocusableElements, setFocus, onFocusFirst]);\n\n const focusLast = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[elements.length - 1]);\n onFocusLast?.();\n }\n }, [getFocusableElements, setFocus, onFocusLast]);\n\n const trapFocusMethod = useCallback(() => {\n trapFocusActiveRef.current = true;\n }, []);\n\n const releaseFocus = useCallback(() => {\n trapFocusActiveRef.current = false;\n }, []);\n\n const handleEscape = useCallback((callback: () => void) => {\n return () => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n callback();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n };\n }, []);\n\n // Handle focus trap\n useEffect(() => {\n if (!trapFocus || !containerRef.current) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && onEscape) {\n onEscape();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const elements = getFocusableElements();\n if (elements.length === 0) return;\n\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n } else {\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }\n };\n\n const current = containerRef.current;\n current.addEventListener('keydown', handleKeyDown);\n return () => {\n current?.removeEventListener('keydown', handleKeyDown);\n };\n }, [trapFocus, onEscape, getFocusableElements]);\n\n // Handle auto focus\n useEffect(() => {\n if (autoFocus) {\n focusFirst();\n }\n }, [autoFocus, focusFirst]);\n\n // Handle focus restoration\n useEffect(() => {\n if (!restoreFocus) return;\n\n previousFocusRef.current = document.activeElement as HTMLElement;\n\n return () => {\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n };\n }, [restoreFocus]);\n\n return {\n containerRef,\n focusRef,\n setFocus,\n focusFirst,\n focusLast,\n trapFocus: trapFocusMethod,\n releaseFocus,\n getFocusableElements,\n handleEscape,\n };\n}\n","\nimport { useRef, useEffect, useCallback } from 'react';\n\nexport interface FocusTrapOptions {\n /** Whether the focus trap is active */\n isActive?: boolean;\n /** Whether to auto-focus the first element when activated */\n autoFocus?: boolean;\n /** Whether to restore focus to the previously focused element when deactivated */\n restoreFocus?: boolean;\n /** Callback when Escape key is pressed */\n onEscape?: () => void;\n /** Selector for focusable elements (optional override) */\n focusableSelector?: string;\n}\n\nexport interface FocusTrapReturn {\n /** Ref to attach to the container element */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Focus the first focusable element */\n focusFirst: () => void;\n /** Focus the last focusable element */\n focusLast: () => void;\n /** Get all focusable elements in the container */\n getFocusableElements: () => HTMLElement[];\n}\n\nconst DEFAULT_FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n '[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]'\n].join(', ');\n\n/**\n * Hook for creating accessible focus traps\n * Useful for modals, dropdowns, and other overlay components\n */\nexport function useFocusTrap(options: FocusTrapOptions = {}): FocusTrapReturn {\n const {\n isActive = false,\n autoFocus = false,\n restoreFocus = false,\n onEscape,\n focusableSelector = DEFAULT_FOCUSABLE_SELECTOR\n } = options;\n\n const containerRef = useRef<HTMLElement>(null);\n const previouslyFocusedElement = useRef<HTMLElement | null>(null);\n\n const getFocusableElements = useCallback((): HTMLElement[] => {\n if (!containerRef.current) return [];\n\n return Array.from(\n containerRef.current.querySelectorAll<HTMLElement>(focusableSelector)\n ).filter((element) => {\n return (\n // visible check\n (!element.hasAttribute('disabled') &&\n !element.hasAttribute('hidden') && element.offsetParent !== null)\n );\n });\n }, [focusableSelector]);\n\n const focusFirst = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n elements[0].focus();\n }\n }, [getFocusableElements]);\n\n const focusLast = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n elements[elements.length - 1].focus();\n }\n }, [getFocusableElements]);\n\n // Handle keyboard events\n useEffect(() => {\n if (!isActive || !containerRef.current) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Handle Escape key\n if (event.key === 'Escape' && onEscape) {\n onEscape();\n return;\n }\n\n // Handle Tab key for focus trapping\n if (event.key === 'Tab') {\n const focusableElements = getFocusableElements();\n if (focusableElements.length === 0) return;\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (event.shiftKey) {\n // Shift + Tab: moving backwards\n if (document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n } else {\n // Tab: moving forwards\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }\n }\n };\n\n const container = containerRef.current;\n container.addEventListener('keydown', handleKeyDown);\n\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n };\n }, [isActive, onEscape, getFocusableElements]);\n\n // Handle focus restoration\n useEffect(() => {\n if (!isActive) return;\n\n // Store the previously focused element\n if (restoreFocus) {\n previouslyFocusedElement.current = document.activeElement as HTMLElement;\n }\n\n // Auto-focus first element if requested\n if (autoFocus) {\n const timer = setTimeout(focusFirst, 0);\n return () => clearTimeout(timer);\n }\n\n return () => {\n // Restore focus when trap is deactivated\n if (restoreFocus && previouslyFocusedElement.current) {\n previouslyFocusedElement.current.focus();\n previouslyFocusedElement.current = null;\n }\n };\n }, [isActive, autoFocus, restoreFocus, focusFirst]);\n\n return {\n containerRef,\n focusFirst,\n focusLast,\n getFocusableElements\n };\n}\n","import { useEffect, useCallback } from 'react';\n\nexport interface KeyboardShortcut {\n /** Key combination (e.g., 'Escape', 'Enter', 'ArrowDown', 'ctrl+s') */\n key: string;\n /** Callback function to execute */\n handler: (event: KeyboardEvent) => void;\n /** Description for documentation/help */\n description?: string;\n /** Whether the shortcut is enabled */\n enabled?: boolean;\n /** Prevent default browser behavior */\n preventDefault?: boolean;\n /** Stop event propagation */\n stopPropagation?: boolean;\n}\n\nexport interface KeyboardShortcutsOptions {\n /** Element to attach listeners to (defaults to document) */\n element?: HTMLElement | Document;\n /** Whether shortcuts are globally enabled */\n enabled?: boolean;\n}\n\n/**\n * Parse key combination string into modifier and key parts\n */\nfunction parseKeyCombo(combo: string) {\n const parts = combo.toLowerCase().split('+');\n const key = parts.pop()!;\n const modifiers = {\n ctrl: parts.includes('ctrl') || parts.includes('control'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta') || parts.includes('cmd')\n };\n return { key, modifiers };\n}\n\n/**\n * Check if event matches the key combination\n */\nfunction matchesKeyCombo(event: KeyboardEvent, combo: string): boolean {\n const { key, modifiers } = parseKeyCombo(combo);\n \n // Check if the main key matches\n const eventKey = event.key.toLowerCase();\n const targetKey = key.toLowerCase();\n \n if (eventKey !== targetKey) {\n return false;\n }\n \n // Check modifiers\n return (\n event.ctrlKey === modifiers.ctrl &&\n event.altKey === modifiers.alt &&\n event.shiftKey === modifiers.shift &&\n event.metaKey === modifiers.meta\n );\n}\n\n/**\n * Hook for managing keyboard shortcuts\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const shortcuts = [\n * {\n * key: 'Escape',\n * handler: () => setIsOpen(false),\n * description: 'Close modal'\n * },\n * {\n * key: 'ctrl+s',\n * handler: (e) => handleSave(),\n * description: 'Save document',\n * preventDefault: true\n * }\n * ];\n * \n * useKeyboardShortcuts(shortcuts);\n * \n * return <div>Content</div>;\n * }\n * ```\n */\nexport function useKeyboardShortcuts(\n shortcuts: KeyboardShortcut[],\n options: KeyboardShortcutsOptions = {}\n): void {\n const { element = document, enabled = true } = options;\n\n const handleKeyDown = useCallback((event: KeyboardEvent) => {\n if (!enabled) return;\n\n for (const shortcut of shortcuts) {\n if (shortcut.enabled === false) continue;\n\n if (matchesKeyCombo(event, shortcut.key)) {\n if (shortcut.preventDefault) {\n event.preventDefault();\n }\n if (shortcut.stopPropagation) {\n event.stopPropagation();\n }\n \n shortcut.handler(event);\n break; // Only handle first matching shortcut\n }\n }\n }, [shortcuts, enabled]);\n\n useEffect(() => {\n if (!enabled) return;\n\n element.addEventListener('keydown', handleKeyDown as EventListener);\n return () => element.removeEventListener('keydown', handleKeyDown as EventListener);\n }, [element, enabled, handleKeyDown]);\n}\n\n/**\n * Hook for common accessibility keyboard shortcuts\n */\nexport function useAccessibilityShortcuts(handlers: {\n onEscape?: () => void;\n onEnter?: () => void;\n onSpace?: () => void;\n onArrowUp?: () => void;\n onArrowDown?: () => void;\n onArrowLeft?: () => void;\n onArrowRight?: () => void;\n onHome?: () => void;\n onEnd?: () => void;\n onTab?: () => void;\n onShiftTab?: () => void;\n}) {\n const shortcuts: KeyboardShortcut[] = [];\n\n if (handlers.onEscape) {\n shortcuts.push({\n key: 'Escape',\n handler: handlers.onEscape,\n description: 'Escape/Cancel'\n });\n }\n\n if (handlers.onEnter) {\n shortcuts.push({\n key: 'Enter',\n handler: handlers.onEnter,\n description: 'Activate/Submit'\n });\n }\n\n if (handlers.onSpace) {\n shortcuts.push({\n key: ' ',\n handler: handlers.onSpace,\n description: 'Activate',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowUp) {\n shortcuts.push({\n key: 'ArrowUp',\n handler: handlers.onArrowUp,\n description: 'Navigate up',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowDown) {\n shortcuts.push({\n key: 'ArrowDown',\n handler: handlers.onArrowDown,\n description: 'Navigate down',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowLeft) {\n shortcuts.push({\n key: 'ArrowLeft',\n handler: handlers.onArrowLeft,\n description: 'Navigate left',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowRight) {\n shortcuts.push({\n key: 'ArrowRight',\n handler: handlers.onArrowRight,\n description: 'Navigate right',\n preventDefault: true\n });\n }\n\n if (handlers.onHome) {\n shortcuts.push({\n key: 'Home',\n handler: handlers.onHome,\n description: 'Go to first item',\n preventDefault: true\n });\n }\n\n if (handlers.onEnd) {\n shortcuts.push({\n key: 'End',\n handler: handlers.onEnd,\n description: 'Go to last item',\n preventDefault: true\n });\n }\n\n if (handlers.onTab) {\n shortcuts.push({\n key: 'Tab',\n handler: handlers.onTab,\n description: 'Navigate forward'\n });\n }\n\n if (handlers.onShiftTab) {\n shortcuts.push({\n key: 'shift+Tab',\n handler: handlers.onShiftTab,\n description: 'Navigate backward'\n });\n }\n\n useKeyboardShortcuts(shortcuts);\n}\n","/**\n * @file useIsMobile Hook\n * @description Hook for detecting mobile viewport using modern matchMedia API\n */\n\nimport { useState, useEffect } from 'react';\n\nconst MOBILE_BREAKPOINT = 768;\n\n/**\n * Hook to detect if the viewport is mobile-sized using matchMedia API.\n * More performant than window resize events.\n * @returns {boolean} True if mobile, false otherwise.\n */\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n // Handle SSR case\n if (typeof window === 'undefined') {\n setIsMobile(false);\n return;\n }\n\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n \n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n\n // Set initial value\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n\n // Add event listener\n mql.addEventListener('change', onChange);\n\n // Cleanup\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n return !!isMobile;\n}\n","/**\n * @file useDataTableState Hook\n * @description Hook for managing DataTable state\n */\n\nimport { useState, useCallback } from 'react';\nimport type { SortingState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table';\n\nexport interface DataTableState {\n sorting: SortingState;\n columnFilters: ColumnFiltersState;\n expanded: ExpandedState;\n pageSize: number;\n pageIndex: number;\n selectedRows: string[];\n}\n\nexport interface DataTableActions {\n setSorting: (sorting: SortingState) => void;\n setColumnFilters: (filters: ColumnFiltersState) => void;\n setExpanded: (expanded: ExpandedState) => void;\n setPageSize: (size: number) => void;\n setPageIndex: (index: number) => void;\n setSelectedRows: (rows: string[]) => void;\n resetState: () => void;\n}\n\nexport interface DataTableComputed {\n paginatedData: any[];\n totalPages: number;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n}\n\nexport interface UseDataTableStateOptions {\n initialPageSize?: number;\n data: any[];\n}\n\n/**\n * Hook for managing DataTable state\n * @param options Configuration options\n * @returns Object containing state, actions, and computed values\n */\nexport function useDataTableState(options: UseDataTableStateOptions) {\n const { initialPageSize = 10, data } = options;\n\n // State\n const [sorting, setSorting] = useState<SortingState>([]);\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);\n const [expanded, setExpanded] = useState<ExpandedState>({});\n const [pageSize, setPageSize] = useState(initialPageSize);\n const [pageIndex, setPageIndex] = useState(0);\n const [selectedRows, setSelectedRows] = useState<string[]>([]);\n\n // Actions\n const resetState = useCallback(() => {\n setSorting([]);\n setColumnFilters([]);\n setExpanded({});\n setPageSize(initialPageSize);\n setPageIndex(0);\n setSelectedRows([]);\n }, [initialPageSize]);\n\n // Computed values - React Compiler handles memoization automatically\n const start = pageIndex * pageSize;\n const end = start + pageSize;\n const paginatedData = data.slice(start, end);\n\n const totalPages = Math.ceil(data.length / pageSize);\n const hasNextPage = pageIndex < totalPages - 1;\n const hasPreviousPage = pageIndex > 0;\n\n return {\n state: {\n sorting,\n columnFilters,\n expanded,\n pageSize,\n pageIndex,\n selectedRows\n },\n actions: {\n setSorting,\n setColumnFilters,\n setExpanded,\n setPageSize,\n setPageIndex,\n setSelectedRows,\n resetState\n },\n computed: {\n paginatedData,\n totalPages,\n hasNextPage,\n hasPreviousPage\n }\n };\n}\n","\nimport { useEffect, useRef, useCallback } from 'react';\nimport { performanceBudgetMonitor, PERFORMANCE_BUDGETS } from '../utils/performance/performanceBudgets';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('usePerformanceMonitor');\n\nexport interface PerformanceMetrics {\n renderTime: number;\n componentName: string;\n timestamp: number;\n}\n\n/**\n * Hook for monitoring component performance with budget validation\n * @param componentName - Name of the component being monitored\n * @param enabled - Whether performance monitoring is enabled\n * @param budgetName - Performance budget to validate against\n */\nexport function usePerformanceMonitor(\n componentName: string, \n enabled = import.meta.env.MODE === 'development',\n budgetName: string = 'COMPONENT_RENDER'\n) {\n const renderStartTime = useRef<number>(0);\n const metrics = useRef<PerformanceMetrics[]>([]);\n\n // Start performance measurement\n const startMeasurement = useCallback(() => {\n if (!enabled) return;\n renderStartTime.current = performance.now();\n }, [enabled]);\n\n // End performance measurement with budget validation\n const endMeasurement = useCallback(() => {\n if (!enabled || renderStartTime.current === 0) return;\n \n const renderTime = performance.now() - renderStartTime.current;\n const metric: PerformanceMetrics = {\n renderTime,\n componentName,\n timestamp: Date.now()\n };\n \n metrics.current.push(metric);\n \n // Keep only last 10 measurements\n if (metrics.current.length > 10) {\n metrics.current = metrics.current.slice(-10);\n }\n \n // Validate against performance budget\n const measurement = performanceBudgetMonitor.measure(budgetName, renderTime, {\n componentName,\n renderCount: metrics.current.length\n });\n \n // Log slow renders in development\n if (!measurement.passed) {\n log.warn(\n `Performance budget exceeded in ${componentName}: ${renderTime.toFixed(2)}ms ` +\n `(budget: ${PERFORMANCE_BUDGETS[budgetName]?.threshold}ms)`\n );\n }\n \n renderStartTime.current = 0;\n }, [enabled, componentName, budgetName]);\n\n // Get performance metrics\n const getMetrics = useCallback(() => {\n return metrics.current.slice();\n }, []);\n\n // Get average render time\n const getAverageRenderTime = useCallback(() => {\n if (metrics.current.length === 0) return 0;\n \n const total = metrics.current.reduce((sum, metric) => sum + metric.renderTime, 0);\n return total / metrics.current.length;\n }, []);\n\n // Get performance budget status\n const getBudgetStatus = useCallback(() => {\n const budget = PERFORMANCE_BUDGETS[budgetName];\n if (!budget) return null;\n\n const averageTime = getAverageRenderTime();\n return {\n budget: budget.threshold,\n average: averageTime,\n passed: averageTime <= budget.threshold,\n efficiency: budget.threshold > 0 ? (budget.threshold - averageTime) / budget.threshold : 0\n };\n }, [budgetName, getAverageRenderTime]);\n\n // Start measurement on every render\n useEffect(() => {\n startMeasurement();\n return endMeasurement;\n });\n\n return {\n getMetrics,\n getAverageRenderTime,\n getBudgetStatus,\n startMeasurement,\n endMeasurement\n };\n}\n\n// Hook for measuring specific operations\nexport function useOperationPerformance(operationName: string, budgetName?: string) {\n const measureOperation = useCallback(async <T>(\n operation: () => Promise<T> | T,\n context?: Record<string, any>\n ): Promise<T> => {\n const start = performance.now();\n const result = await operation();\n const duration = performance.now() - start;\n \n const budget = budgetName || 'COMPONENT_RENDER';\n performanceBudgetMonitor.measure(budget, duration, {\n operation: operationName,\n ...context\n });\n \n return result;\n }, [operationName, budgetName]);\n\n return { measureOperation };\n}\n","/**\n * @file File URL Cache Hook\n * @package @jmruthers/pace-core\n * @module Hooks\n *\n * Centralized caching hook for file URLs to prevent duplicate requests\n * and improve performance across components.\n *\n * Features:\n * - TTL-based caching matching signed URL expiration (3600s)\n * - Automatic cache cleanup\n * - Supports both public and signed URLs\n * - Thread-safe cache operations\n *\n * @example\n * ```tsx\n * import { useFileUrlCache } from '@jmruthers/pace-core';\n *\n * function MyComponent() {\n * const { getUrl, setUrl, clearCache } = useFileUrlCache();\n *\n * const url = await getUrl(fileReference, supabase, organisationId);\n * return <img src={url} alt=\"File\" />;\n * }\n * ```\n */\n\nimport { useRef, useCallback } from 'react';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { FileReference } from '../types/file-reference';\nimport { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';\n\ninterface CachedUrl {\n url: string;\n expiresAt: number; // Timestamp in milliseconds\n}\n\n// Global cache shared across all hook instances\nconst globalUrlCache = new Map<string, CachedUrl>();\n\n// Cache size limit to prevent memory leaks\nconst MAX_CACHE_SIZE = 500;\n\n// Default TTL matches signed URL expiration (3600 seconds = 1 hour)\nconst DEFAULT_TTL_MS = 3600 * 1000;\n\n/**\n * Generate cache key from file reference\n */\nfunction getCacheKey(fileReference: FileReference): string {\n return `file-url:${fileReference.id}:${fileReference.is_public ? 'public' : 'private'}`;\n}\n\n/**\n * Clean up expired entries and enforce size limit\n */\nfunction cleanupCache(): void {\n const now = Date.now();\n \n // Remove expired entries\n for (const [key, value] of globalUrlCache.entries()) {\n if (value.expiresAt < now) {\n globalUrlCache.delete(key);\n }\n }\n \n // Enforce size limit by removing oldest entries\n if (globalUrlCache.size > MAX_CACHE_SIZE) {\n const entries = Array.from(globalUrlCache.entries());\n // Sort by expiration time (oldest first)\n entries.sort((a, b) => a[1].expiresAt - b[1].expiresAt);\n \n // Remove oldest 20% of entries\n const toRemove = Math.floor(MAX_CACHE_SIZE * 0.2);\n for (let i = 0; i < toRemove && i < entries.length; i++) {\n globalUrlCache.delete(entries[i][0]);\n }\n }\n}\n\nexport interface UseFileUrlCacheReturn {\n /**\n * Get URL for a file reference, using cache if available\n * @param fileReference - File reference to get URL for\n * @param supabase - Supabase client instance\n * @param organisationId - Organisation ID for signed URLs\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n * @returns Promise resolving to URL string or null\n */\n getUrl: (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl?: number\n ) => Promise<string | null>;\n \n /**\n * Set URL in cache\n * @param fileReference - File reference\n * @param url - URL to cache\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n */\n setUrl: (fileReference: FileReference, url: string, ttl?: number) => void;\n \n /**\n * Get URL from cache without generating if missing\n * @param fileReference - File reference\n * @returns Cached URL or null if not in cache or expired\n */\n getCachedUrl: (fileReference: FileReference) => string | null;\n \n /**\n * Clear cache for a specific file reference\n * @param fileReference - File reference to clear\n */\n clearFile: (fileReference: FileReference) => void;\n \n /**\n * Clear all cached URLs\n */\n clearCache: () => void;\n \n /**\n * Get cache statistics\n */\n getCacheStats: () => { size: number; maxSize: number };\n}\n\n/**\n * Hook for centralized file URL caching\n * \n * This hook provides a shared cache for file URLs across all components,\n * preventing duplicate requests for the same file.\n * \n * @returns Cache operations and utilities\n */\nexport function useFileUrlCache(): UseFileUrlCacheReturn {\n // Use ref to ensure stable reference across renders\n const cleanupIntervalRef = useRef<number | null>(null);\n \n // Set up periodic cleanup (every 5 minutes)\n if (cleanupIntervalRef.current === null && typeof window !== 'undefined') {\n cleanupIntervalRef.current = window.setInterval(() => {\n cleanupCache();\n }, 5 * 60 * 1000); // 5 minutes\n }\n \n const getUrl = useCallback(async (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl: number = DEFAULT_TTL_MS\n ): Promise<string | null> => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n // Return cached URL if still valid\n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n // Generate new URL\n let url: string | null = null;\n \n try {\n if (fileReference.is_public) {\n // Public files: generate public URL (synchronous)\n url = getPublicUrl(supabase, fileReference.file_path, true);\n } else {\n // Private files: generate signed URL (async)\n const signedUrlResult = await getSignedUrl(supabase, fileReference.file_path, {\n appName: 'pace-core',\n orgId: organisationId,\n expiresIn: Math.floor(ttl / 1000) // Convert ms to seconds\n });\n url = signedUrlResult?.url || null;\n }\n \n // Cache the URL if generated successfully\n if (url) {\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: now + ttl\n });\n cleanupCache(); // Clean up after adding\n }\n \n return url;\n } catch (error) {\n console.error('Failed to generate file URL:', error);\n return null;\n }\n }, []);\n \n const setUrl = useCallback((\n fileReference: FileReference,\n url: string,\n ttl: number = DEFAULT_TTL_MS\n ): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: Date.now() + ttl\n });\n cleanupCache();\n }, []);\n \n const getCachedUrl = useCallback((fileReference: FileReference): string | null => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n return null;\n }, []);\n \n const clearFile = useCallback((fileReference: FileReference): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.delete(cacheKey);\n }, []);\n \n const clearCache = useCallback((): void => {\n globalUrlCache.clear();\n }, []);\n \n const getCacheStats = useCallback(() => {\n return {\n size: globalUrlCache.size,\n maxSize: MAX_CACHE_SIZE\n };\n }, []);\n \n return {\n getUrl,\n setUrl,\n getCachedUrl,\n clearFile,\n clearCache,\n getCacheStats\n };\n}\n\n","/**\n * React hook for storage operations\n */\n\nimport { useState, useCallback } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { \n StorageUploadOptions, \n StorageUploadResult, \n StorageFileInfo,\n StorageListOptions,\n StorageListResult,\n uploadFile,\n getPublicUrl,\n getSignedUrl,\n deleteFile,\n listFiles,\n archiveFile\n} from '../utils/storage';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useStorage');\n\nexport interface UseStorageOptions {\n supabase: SupabaseClient;\n appName: string;\n orgId: string;\n}\n\nexport interface UseStorageReturn {\n // Upload\n uploadFile: (file: File, options?: Partial<StorageUploadOptions>) => Promise<StorageUploadResult>;\n isUploading: boolean;\n uploadError: string | null;\n \n // URLs\n getPublicUrl: (path: string) => string;\n getSignedUrl: (path: string, expiresIn?: number) => Promise<string | null>;\n getFileUrl: (path: string) => string; // Alias for getPublicUrl\n \n // File management\n deleteFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n archiveFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n \n // Listing\n listFiles: (options?: Partial<StorageListOptions>) => Promise<StorageListResult>;\n isListing: boolean;\n listError: string | null;\n isLoading: boolean; // Alias for isListing\n error: string | null; // Alias for listError\n \n // State\n files: StorageFileInfo[];\n refreshFiles: () => Promise<void>;\n}\n\n/**\n * Hook for storage operations with app and organisation context\n */\nexport function useStorage({ supabase, appName, orgId }: UseStorageOptions): UseStorageReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n const [isListing, setIsListing] = useState(false);\n const [listError, setListError] = useState<string | null>(null);\n const [files, setFiles] = useState<StorageFileInfo[]>([]);\n\n // Upload file\n const handleUploadFile = useCallback(async (\n file: File, \n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadError(null);\n\n try {\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n if (result.success) {\n // Refresh file list\n await refreshFiles();\n } else {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n }\n }, [supabase, appName, orgId]);\n\n // Get public URL\n const handleGetPublicUrl = useCallback((path: string): string => {\n return getPublicUrl(supabase, path);\n }, [supabase]);\n\n // Get signed URL\n const handleGetSignedUrl = useCallback(async (\n path: string, \n expiresIn?: number\n ): Promise<string | null> => {\n try {\n const result = await getSignedUrl(supabase, path, {\n appName,\n orgId,\n expiresIn\n });\n return result?.url || null;\n } catch (error) {\n log.error('Failed to get signed URL:', error);\n return null;\n }\n }, [supabase, appName, orgId]);\n\n // Delete file\n const handleDeleteFile = useCallback(async (path: string) => {\n try {\n const result = await deleteFile(supabase, path);\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Delete failed'\n };\n }\n }, [supabase]);\n\n // Archive file\n const handleArchiveFile = useCallback(async (path: string) => {\n try {\n const result = await archiveFile(supabase, path, { appName, orgId });\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Archive failed'\n };\n }\n }, [supabase, appName, orgId]);\n\n // List files\n const handleListFiles = useCallback(async (\n options: Partial<StorageListOptions> = {}\n ): Promise<StorageListResult> => {\n setIsListing(true);\n setListError(null);\n\n try {\n const listOptions: StorageListOptions = {\n appName,\n orgId,\n ...options\n };\n\n const result = await listFiles(supabase, listOptions);\n setFiles(result.files);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'List failed';\n setListError(errorMessage);\n return { files: [], totalCount: 0, hasMore: false };\n } finally {\n setIsListing(false);\n }\n }, [supabase, appName, orgId]);\n\n // Refresh files\n const refreshFiles = useCallback(async () => {\n await handleListFiles();\n }, [handleListFiles]);\n\n return {\n // Upload\n uploadFile: handleUploadFile,\n isUploading,\n uploadError,\n \n // URLs\n getPublicUrl: handleGetPublicUrl,\n getSignedUrl: handleGetSignedUrl,\n getFileUrl: handleGetPublicUrl, // Alias for getPublicUrl\n \n // File management\n deleteFile: handleDeleteFile,\n archiveFile: handleArchiveFile,\n \n // Listing\n listFiles: handleListFiles,\n isListing,\n listError,\n isLoading: isListing, // Alias for isListing\n error: listError, // Alias for listError\n \n // State\n files,\n refreshFiles\n };\n}\n\n/**\n * Hook for file upload with progress tracking\n */\nexport function useFileUpload({ supabase, appName, orgId }: UseStorageOptions) {\n const [uploadProgress, setUploadProgress] = useState(0);\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const uploadWithProgress = useCallback(async (\n file: File,\n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadProgress(0);\n setUploadError(null);\n\n try {\n // Simulate progress (Supabase doesn't provide real progress)\n const progressInterval = setInterval(() => {\n setUploadProgress(prev => Math.min(prev + 10, 90));\n }, 100);\n\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n clearInterval(progressInterval);\n setUploadProgress(100);\n\n if (!result.success) {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n setTimeout(() => setUploadProgress(0), 1000);\n }\n }, [supabase, appName, orgId]);\n\n return {\n uploadWithProgress,\n uploadProgress,\n isUploading,\n uploadError\n };\n}\n"],"mappings":"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","names":["useRef","useEffect","useCallback","useEffect","useCallback","useEffect","useState","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useState","useCallback","log","useState","useCallback"]}
1
+ {"version":3,"sources":["../src/hooks/useFocusManagement.ts","../src/hooks/useFocusTrap.ts","../src/hooks/useKeyboardShortcuts.ts","../src/hooks/useIsMobile.ts","../src/hooks/useDataTableState.ts","../src/hooks/usePerformanceMonitor.ts","../src/hooks/useFileUrlCache.ts","../src/hooks/useStorage.ts"],"sourcesContent":["\nimport { useRef, useCallback, useEffect } from 'react';\n\n/**\n * Options for the useFocusManagement hook.\n */\nexport interface FocusManagementOptions {\n trapFocus?: boolean;\n autoFocus?: boolean;\n restoreFocus?: boolean;\n onEscape?: () => void;\n onFocusFirst?: () => void;\n onFocusLast?: () => void;\n}\n\n/**\n * Return value of the useFocusManagement hook.\n * Provides focus management utilities for accessible components.\n */\nexport interface FocusManagementReturn {\n containerRef: React.RefObject<HTMLDivElement | null>;\n focusRef: React.RefObject<HTMLElement | null>;\n setFocus: (element: HTMLElement | null) => void;\n focusFirst: () => void;\n focusLast: () => void;\n trapFocus: () => void;\n releaseFocus: () => void;\n getFocusableElements: () => HTMLElement[];\n handleEscape: (callback: () => void) => () => void;\n}\n\n/**\n * Hook for managing focus in accessible components.\n * Provides focus trapping, restoration, and navigation utilities.\n * \n * @param options - Focus management configuration\n * @returns Focus management utilities and refs\n */\nexport function useFocusManagement(options: FocusManagementOptions = {}): FocusManagementReturn {\n const { \n trapFocus = false, \n autoFocus = false, \n restoreFocus = false,\n onEscape,\n onFocusFirst,\n onFocusLast \n } = options;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const focusRef = useRef<HTMLElement | null>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const trapFocusActiveRef = useRef<boolean>(false);\n\n const setFocus = useCallback((element: HTMLElement | null) => {\n focusRef.current = element;\n element?.focus();\n }, []);\n\n const getFocusableElements = useCallback((): HTMLElement[] => {\n if (!containerRef.current) return [];\n\n return Array.from(\n containerRef.current.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute('disabled') && !el.hasAttribute('hidden'));\n }, []);\n\n const focusFirst = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[0]);\n onFocusFirst?.();\n }\n }, [getFocusableElements, setFocus, onFocusFirst]);\n\n const focusLast = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[elements.length - 1]);\n onFocusLast?.();\n }\n }, [getFocusableElements, setFocus, onFocusLast]);\n\n const trapFocusMethod = useCallback(() => {\n trapFocusActiveRef.current = true;\n }, []);\n\n const releaseFocus = useCallback(() => {\n trapFocusActiveRef.current = false;\n }, []);\n\n const handleEscape = useCallback((callback: () => void) => {\n return () => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n callback();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n };\n }, []);\n\n // Handle focus trap\n useEffect(() => {\n if (!trapFocus || !containerRef.current) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && onEscape) {\n onEscape();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const elements = getFocusableElements();\n if (elements.length === 0) return;\n\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n } else {\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }\n };\n\n const current = containerRef.current;\n current.addEventListener('keydown', handleKeyDown);\n return () => {\n current?.removeEventListener('keydown', handleKeyDown);\n };\n }, [trapFocus, onEscape, getFocusableElements]);\n\n // Handle auto focus\n useEffect(() => {\n if (autoFocus) {\n focusFirst();\n }\n }, [autoFocus, focusFirst]);\n\n // Handle focus restoration\n useEffect(() => {\n if (!restoreFocus) return;\n\n previousFocusRef.current = document.activeElement as HTMLElement;\n\n return () => {\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n };\n }, [restoreFocus]);\n\n return {\n containerRef,\n focusRef,\n setFocus,\n focusFirst,\n focusLast,\n trapFocus: trapFocusMethod,\n releaseFocus,\n getFocusableElements,\n handleEscape,\n };\n}\n","\nimport { useRef, useEffect, useCallback } from 'react';\n\n/**\n * Options for the useFocusTrap hook.\n */\nexport interface FocusTrapOptions {\n /** Whether the focus trap is active */\n isActive?: boolean;\n /** Whether to auto-focus the first element when activated */\n autoFocus?: boolean;\n /** Whether to restore focus to the previously focused element when deactivated */\n restoreFocus?: boolean;\n /** Callback when Escape key is pressed */\n onEscape?: () => void;\n /** Selector for focusable elements (optional override) */\n focusableSelector?: string;\n}\n\nexport interface FocusTrapReturn {\n /** Ref to attach to the container element */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Focus the first focusable element */\n focusFirst: () => void;\n /** Focus the last focusable element */\n focusLast: () => void;\n /** Get all focusable elements in the container */\n getFocusableElements: () => HTMLElement[];\n}\n\nconst DEFAULT_FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n '[href]',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]'\n].join(', ');\n\n/**\n * Hook for creating accessible focus traps\n * Useful for modals, dropdowns, and other overlay components\n */\nexport function useFocusTrap(options: FocusTrapOptions = {}): FocusTrapReturn {\n const {\n isActive = false,\n autoFocus = false,\n restoreFocus = false,\n onEscape,\n focusableSelector = DEFAULT_FOCUSABLE_SELECTOR\n } = options;\n\n const containerRef = useRef<HTMLElement>(null);\n const previouslyFocusedElement = useRef<HTMLElement | null>(null);\n\n const getFocusableElements = useCallback((): HTMLElement[] => {\n if (!containerRef.current) return [];\n\n return Array.from(\n containerRef.current.querySelectorAll<HTMLElement>(focusableSelector)\n ).filter((element) => {\n return (\n // visible check\n (!element.hasAttribute('disabled') &&\n !element.hasAttribute('hidden') && element.offsetParent !== null)\n );\n });\n }, [focusableSelector]);\n\n const focusFirst = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n elements[0].focus();\n }\n }, [getFocusableElements]);\n\n const focusLast = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n elements[elements.length - 1].focus();\n }\n }, [getFocusableElements]);\n\n // Handle keyboard events\n useEffect(() => {\n if (!isActive || !containerRef.current) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Handle Escape key\n if (event.key === 'Escape' && onEscape) {\n onEscape();\n return;\n }\n\n // Handle Tab key for focus trapping\n if (event.key === 'Tab') {\n const focusableElements = getFocusableElements();\n if (focusableElements.length === 0) return;\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (event.shiftKey) {\n // Shift + Tab: moving backwards\n if (document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n } else {\n // Tab: moving forwards\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }\n }\n };\n\n const container = containerRef.current;\n container.addEventListener('keydown', handleKeyDown);\n\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n };\n }, [isActive, onEscape, getFocusableElements]);\n\n // Handle focus restoration\n useEffect(() => {\n if (!isActive) return;\n\n // Store the previously focused element\n if (restoreFocus) {\n previouslyFocusedElement.current = document.activeElement as HTMLElement;\n }\n\n // Auto-focus first element if requested\n if (autoFocus) {\n const timer = setTimeout(focusFirst, 0);\n return () => clearTimeout(timer);\n }\n\n return () => {\n // Restore focus when trap is deactivated\n if (restoreFocus && previouslyFocusedElement.current) {\n previouslyFocusedElement.current.focus();\n previouslyFocusedElement.current = null;\n }\n };\n }, [isActive, autoFocus, restoreFocus, focusFirst]);\n\n return {\n containerRef,\n focusFirst,\n focusLast,\n getFocusableElements\n };\n}\n","import { useEffect, useCallback } from 'react';\n\n/**\n * Keyboard shortcut definition.\n * Defines a key combination and its handler function.\n */\nexport interface KeyboardShortcut {\n /** Key combination (e.g., 'Escape', 'Enter', 'ArrowDown', 'ctrl+s') */\n key: string;\n /** Callback function to execute */\n handler: (event: KeyboardEvent) => void;\n /** Description for documentation/help */\n description?: string;\n /** Whether the shortcut is enabled */\n enabled?: boolean;\n /** Prevent default browser behavior */\n preventDefault?: boolean;\n /** Stop event propagation */\n stopPropagation?: boolean;\n}\n\nexport interface KeyboardShortcutsOptions {\n /** Element to attach listeners to (defaults to document) */\n element?: HTMLElement | Document;\n /** Whether shortcuts are globally enabled */\n enabled?: boolean;\n}\n\n/**\n * Parse key combination string into modifier and key parts\n */\nfunction parseKeyCombo(combo: string) {\n const parts = combo.toLowerCase().split('+');\n const key = parts.pop()!;\n const modifiers = {\n ctrl: parts.includes('ctrl') || parts.includes('control'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta') || parts.includes('cmd')\n };\n return { key, modifiers };\n}\n\n/**\n * Check if event matches the key combination\n */\nfunction matchesKeyCombo(event: KeyboardEvent, combo: string): boolean {\n const { key, modifiers } = parseKeyCombo(combo);\n \n // Check if the main key matches\n const eventKey = event.key.toLowerCase();\n const targetKey = key.toLowerCase();\n \n if (eventKey !== targetKey) {\n return false;\n }\n \n // Check modifiers\n return (\n event.ctrlKey === modifiers.ctrl &&\n event.altKey === modifiers.alt &&\n event.shiftKey === modifiers.shift &&\n event.metaKey === modifiers.meta\n );\n}\n\n/**\n * Hook for managing keyboard shortcuts\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const shortcuts = [\n * {\n * key: 'Escape',\n * handler: () => setIsOpen(false),\n * description: 'Close modal'\n * },\n * {\n * key: 'ctrl+s',\n * handler: (e) => handleSave(),\n * description: 'Save document',\n * preventDefault: true\n * }\n * ];\n * \n * useKeyboardShortcuts(shortcuts);\n * \n * return <div>Content</div>;\n * }\n * ```\n */\nexport function useKeyboardShortcuts(\n shortcuts: KeyboardShortcut[],\n options: KeyboardShortcutsOptions = {}\n): void {\n const { element = document, enabled = true } = options;\n\n const handleKeyDown = useCallback((event: KeyboardEvent) => {\n if (!enabled) return;\n\n for (const shortcut of shortcuts) {\n if (shortcut.enabled === false) continue;\n\n if (matchesKeyCombo(event, shortcut.key)) {\n if (shortcut.preventDefault) {\n event.preventDefault();\n }\n if (shortcut.stopPropagation) {\n event.stopPropagation();\n }\n \n shortcut.handler(event);\n break; // Only handle first matching shortcut\n }\n }\n }, [shortcuts, enabled]);\n\n useEffect(() => {\n if (!enabled) return;\n\n element.addEventListener('keydown', handleKeyDown as EventListener);\n return () => element.removeEventListener('keydown', handleKeyDown as EventListener);\n }, [element, enabled, handleKeyDown]);\n}\n\n/**\n * Hook for common accessibility keyboard shortcuts\n */\nexport function useAccessibilityShortcuts(handlers: {\n onEscape?: () => void;\n onEnter?: () => void;\n onSpace?: () => void;\n onArrowUp?: () => void;\n onArrowDown?: () => void;\n onArrowLeft?: () => void;\n onArrowRight?: () => void;\n onHome?: () => void;\n onEnd?: () => void;\n onTab?: () => void;\n onShiftTab?: () => void;\n}) {\n const shortcuts: KeyboardShortcut[] = [];\n\n if (handlers.onEscape) {\n shortcuts.push({\n key: 'Escape',\n handler: handlers.onEscape,\n description: 'Escape/Cancel'\n });\n }\n\n if (handlers.onEnter) {\n shortcuts.push({\n key: 'Enter',\n handler: handlers.onEnter,\n description: 'Activate/Submit'\n });\n }\n\n if (handlers.onSpace) {\n shortcuts.push({\n key: ' ',\n handler: handlers.onSpace,\n description: 'Activate',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowUp) {\n shortcuts.push({\n key: 'ArrowUp',\n handler: handlers.onArrowUp,\n description: 'Navigate up',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowDown) {\n shortcuts.push({\n key: 'ArrowDown',\n handler: handlers.onArrowDown,\n description: 'Navigate down',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowLeft) {\n shortcuts.push({\n key: 'ArrowLeft',\n handler: handlers.onArrowLeft,\n description: 'Navigate left',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowRight) {\n shortcuts.push({\n key: 'ArrowRight',\n handler: handlers.onArrowRight,\n description: 'Navigate right',\n preventDefault: true\n });\n }\n\n if (handlers.onHome) {\n shortcuts.push({\n key: 'Home',\n handler: handlers.onHome,\n description: 'Go to first item',\n preventDefault: true\n });\n }\n\n if (handlers.onEnd) {\n shortcuts.push({\n key: 'End',\n handler: handlers.onEnd,\n description: 'Go to last item',\n preventDefault: true\n });\n }\n\n if (handlers.onTab) {\n shortcuts.push({\n key: 'Tab',\n handler: handlers.onTab,\n description: 'Navigate forward'\n });\n }\n\n if (handlers.onShiftTab) {\n shortcuts.push({\n key: 'shift+Tab',\n handler: handlers.onShiftTab,\n description: 'Navigate backward'\n });\n }\n\n useKeyboardShortcuts(shortcuts);\n}\n","/**\n * @file useIsMobile Hook\n * @description Hook for detecting mobile viewport using modern matchMedia API\n */\n\nimport { useState, useEffect } from 'react';\n\nconst MOBILE_BREAKPOINT = 768;\n\n/**\n * Hook to detect if the viewport is mobile-sized using matchMedia API.\n * More performant than window resize events.\n * @returns {boolean} True if mobile, false otherwise.\n */\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n // Handle SSR case\n if (typeof window === 'undefined') {\n setIsMobile(false);\n return;\n }\n\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n \n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n\n // Set initial value\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n\n // Add event listener\n mql.addEventListener('change', onChange);\n\n // Cleanup\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n return !!isMobile;\n}\n","/**\n * @file useDataTableState Hook\n * @description Hook for managing DataTable state\n */\n\nimport { useState, useCallback } from 'react';\nimport type { SortingState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table';\n\nexport interface DataTableState {\n sorting: SortingState;\n columnFilters: ColumnFiltersState;\n expanded: ExpandedState;\n pageSize: number;\n pageIndex: number;\n selectedRows: string[];\n}\n\nexport interface DataTableActions {\n setSorting: (sorting: SortingState) => void;\n setColumnFilters: (filters: ColumnFiltersState) => void;\n setExpanded: (expanded: ExpandedState) => void;\n setPageSize: (size: number) => void;\n setPageIndex: (index: number) => void;\n setSelectedRows: (rows: string[]) => void;\n resetState: () => void;\n}\n\nexport interface DataTableComputed {\n paginatedData: any[];\n totalPages: number;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n}\n\nexport interface UseDataTableStateOptions {\n initialPageSize?: number;\n data: any[];\n}\n\n/**\n * Hook for managing DataTable state\n * @param options Configuration options\n * @returns Object containing state, actions, and computed values\n */\nexport function useDataTableState(options: UseDataTableStateOptions) {\n const { initialPageSize = 10, data } = options;\n\n // State\n const [sorting, setSorting] = useState<SortingState>([]);\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);\n const [expanded, setExpanded] = useState<ExpandedState>({});\n const [pageSize, setPageSize] = useState(initialPageSize);\n const [pageIndex, setPageIndex] = useState(0);\n const [selectedRows, setSelectedRows] = useState<string[]>([]);\n\n // Actions\n const resetState = useCallback(() => {\n setSorting([]);\n setColumnFilters([]);\n setExpanded({});\n setPageSize(initialPageSize);\n setPageIndex(0);\n setSelectedRows([]);\n }, [initialPageSize]);\n\n // Computed values - React Compiler handles memoization automatically\n const start = pageIndex * pageSize;\n const end = start + pageSize;\n const paginatedData = data.slice(start, end);\n\n const totalPages = Math.ceil(data.length / pageSize);\n const hasNextPage = pageIndex < totalPages - 1;\n const hasPreviousPage = pageIndex > 0;\n\n return {\n state: {\n sorting,\n columnFilters,\n expanded,\n pageSize,\n pageIndex,\n selectedRows\n },\n actions: {\n setSorting,\n setColumnFilters,\n setExpanded,\n setPageSize,\n setPageIndex,\n setSelectedRows,\n resetState\n },\n computed: {\n paginatedData,\n totalPages,\n hasNextPage,\n hasPreviousPage\n }\n };\n}\n","\nimport { useEffect, useRef, useCallback } from 'react';\nimport { performanceBudgetMonitor, PERFORMANCE_BUDGETS } from '../utils/performance/performanceBudgets';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('usePerformanceMonitor');\n\n/**\n * Performance metrics interface.\n * Represents performance measurement data for components or operations.\n */\nexport interface PerformanceMetrics {\n renderTime: number;\n componentName: string;\n timestamp: number;\n}\n\n/**\n * Hook for monitoring component performance with budget validation\n * @param componentName - Name of the component being monitored\n * @param enabled - Whether performance monitoring is enabled\n * @param budgetName - Performance budget to validate against\n */\nexport function usePerformanceMonitor(\n componentName: string, \n enabled = import.meta.env.MODE === 'development',\n budgetName: string = 'COMPONENT_RENDER'\n) {\n const renderStartTime = useRef<number>(0);\n const metrics = useRef<PerformanceMetrics[]>([]);\n\n // Start performance measurement\n const startMeasurement = useCallback(() => {\n if (!enabled) return;\n renderStartTime.current = performance.now();\n }, [enabled]);\n\n // End performance measurement with budget validation\n const endMeasurement = useCallback(() => {\n if (!enabled || renderStartTime.current === 0) return;\n \n const renderTime = performance.now() - renderStartTime.current;\n const metric: PerformanceMetrics = {\n renderTime,\n componentName,\n timestamp: Date.now()\n };\n \n metrics.current.push(metric);\n \n // Keep only last 10 measurements\n if (metrics.current.length > 10) {\n metrics.current = metrics.current.slice(-10);\n }\n \n // Validate against performance budget\n const measurement = performanceBudgetMonitor.measure(budgetName, renderTime, {\n componentName,\n renderCount: metrics.current.length\n });\n \n // Log slow renders in development\n if (!measurement.passed) {\n log.warn(\n `Performance budget exceeded in ${componentName}: ${renderTime.toFixed(2)}ms ` +\n `(budget: ${PERFORMANCE_BUDGETS[budgetName]?.threshold}ms)`\n );\n }\n \n renderStartTime.current = 0;\n }, [enabled, componentName, budgetName]);\n\n // Get performance metrics\n const getMetrics = useCallback(() => {\n return metrics.current.slice();\n }, []);\n\n // Get average render time\n const getAverageRenderTime = useCallback(() => {\n if (metrics.current.length === 0) return 0;\n \n const total = metrics.current.reduce((sum, metric) => sum + metric.renderTime, 0);\n return total / metrics.current.length;\n }, []);\n\n // Get performance budget status\n const getBudgetStatus = useCallback(() => {\n const budget = PERFORMANCE_BUDGETS[budgetName];\n if (!budget) return null;\n\n const averageTime = getAverageRenderTime();\n return {\n budget: budget.threshold,\n average: averageTime,\n passed: averageTime <= budget.threshold,\n efficiency: budget.threshold > 0 ? (budget.threshold - averageTime) / budget.threshold : 0\n };\n }, [budgetName, getAverageRenderTime]);\n\n // Start measurement on every render\n useEffect(() => {\n startMeasurement();\n return endMeasurement;\n });\n\n return {\n getMetrics,\n getAverageRenderTime,\n getBudgetStatus,\n startMeasurement,\n endMeasurement\n };\n}\n\n// Hook for measuring specific operations\nexport function useOperationPerformance(operationName: string, budgetName?: string) {\n const measureOperation = useCallback(async <T>(\n operation: () => Promise<T> | T,\n context?: Record<string, any>\n ): Promise<T> => {\n const start = performance.now();\n const result = await operation();\n const duration = performance.now() - start;\n \n const budget = budgetName || 'COMPONENT_RENDER';\n performanceBudgetMonitor.measure(budget, duration, {\n operation: operationName,\n ...context\n });\n \n return result;\n }, [operationName, budgetName]);\n\n return { measureOperation };\n}\n","/**\n * @file File URL Cache Hook\n * @package @jmruthers/pace-core\n * @module Hooks\n *\n * Centralized caching hook for file URLs to prevent duplicate requests\n * and improve performance across components.\n *\n * Features:\n * - TTL-based caching matching signed URL expiration (3600s)\n * - Automatic cache cleanup\n * - Supports both public and signed URLs\n * - Thread-safe cache operations\n *\n * @example\n * ```tsx\n * import { useFileUrlCache } from '@jmruthers/pace-core';\n *\n * function MyComponent() {\n * const { getUrl, setUrl, clearCache } = useFileUrlCache();\n *\n * const url = await getUrl(fileReference, supabase, organisationId);\n * return <img src={url} alt=\"File\" />;\n * }\n * ```\n */\n\nimport { useRef, useCallback } from 'react';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { FileReference } from '../types/file-reference';\nimport { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';\n\ninterface CachedUrl {\n url: string;\n expiresAt: number; // Timestamp in milliseconds\n}\n\n// Global cache shared across all hook instances\nconst globalUrlCache = new Map<string, CachedUrl>();\n\n// Cache size limit to prevent memory leaks\nconst MAX_CACHE_SIZE = 500;\n\n// Default TTL matches signed URL expiration (3600 seconds = 1 hour)\nconst DEFAULT_TTL_MS = 3600 * 1000;\n\n/**\n * Generate cache key from file reference\n */\nfunction getCacheKey(fileReference: FileReference): string {\n return `file-url:${fileReference.id}:${fileReference.is_public ? 'public' : 'private'}`;\n}\n\n/**\n * Clean up expired entries and enforce size limit\n */\nfunction cleanupCache(): void {\n const now = Date.now();\n \n // Remove expired entries\n for (const [key, value] of globalUrlCache.entries()) {\n if (value.expiresAt < now) {\n globalUrlCache.delete(key);\n }\n }\n \n // Enforce size limit by removing oldest entries\n if (globalUrlCache.size > MAX_CACHE_SIZE) {\n const entries = Array.from(globalUrlCache.entries());\n // Sort by expiration time (oldest first)\n entries.sort((a, b) => a[1].expiresAt - b[1].expiresAt);\n \n // Remove oldest 20% of entries\n const toRemove = Math.floor(MAX_CACHE_SIZE * 0.2);\n for (let i = 0; i < toRemove && i < entries.length; i++) {\n globalUrlCache.delete(entries[i][0]);\n }\n }\n}\n\nexport interface UseFileUrlCacheReturn {\n /**\n * Get URL for a file reference, using cache if available\n * @param fileReference - File reference to get URL for\n * @param supabase - Supabase client instance\n * @param organisationId - Organisation ID for signed URLs\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n * @returns Promise resolving to URL string or null\n */\n getUrl: (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl?: number\n ) => Promise<string | null>;\n \n /**\n * Set URL in cache\n * @param fileReference - File reference\n * @param url - URL to cache\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n */\n setUrl: (fileReference: FileReference, url: string, ttl?: number) => void;\n \n /**\n * Get URL from cache without generating if missing\n * @param fileReference - File reference\n * @returns Cached URL or null if not in cache or expired\n */\n getCachedUrl: (fileReference: FileReference) => string | null;\n \n /**\n * Clear cache for a specific file reference\n * @param fileReference - File reference to clear\n */\n clearFile: (fileReference: FileReference) => void;\n \n /**\n * Clear all cached URLs\n */\n clearCache: () => void;\n \n /**\n * Get cache statistics\n */\n getCacheStats: () => { size: number; maxSize: number };\n}\n\n/**\n * Hook for centralized file URL caching\n * \n * This hook provides a shared cache for file URLs across all components,\n * preventing duplicate requests for the same file.\n * \n * @returns Cache operations and utilities\n */\nexport function useFileUrlCache(): UseFileUrlCacheReturn {\n // Use ref to ensure stable reference across renders\n const cleanupIntervalRef = useRef<number | null>(null);\n \n // Set up periodic cleanup (every 5 minutes)\n if (cleanupIntervalRef.current === null && typeof window !== 'undefined') {\n cleanupIntervalRef.current = window.setInterval(() => {\n cleanupCache();\n }, 5 * 60 * 1000); // 5 minutes\n }\n \n const getUrl = useCallback(async (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl: number = DEFAULT_TTL_MS\n ): Promise<string | null> => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n // Return cached URL if still valid\n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n // Generate new URL\n let url: string | null = null;\n \n try {\n if (fileReference.is_public) {\n // Public files: generate public URL (synchronous)\n url = getPublicUrl(supabase, fileReference.file_path, true);\n } else {\n // Private files: generate signed URL (async)\n const signedUrlResult = await getSignedUrl(supabase, fileReference.file_path, {\n appName: 'pace-core',\n orgId: organisationId,\n expiresIn: Math.floor(ttl / 1000) // Convert ms to seconds\n });\n url = signedUrlResult?.url || null;\n }\n \n // Cache the URL if generated successfully\n if (url) {\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: now + ttl\n });\n cleanupCache(); // Clean up after adding\n }\n \n return url;\n } catch (error) {\n console.error('Failed to generate file URL:', error);\n return null;\n }\n }, []);\n \n const setUrl = useCallback((\n fileReference: FileReference,\n url: string,\n ttl: number = DEFAULT_TTL_MS\n ): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: Date.now() + ttl\n });\n cleanupCache();\n }, []);\n \n const getCachedUrl = useCallback((fileReference: FileReference): string | null => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n return null;\n }, []);\n \n const clearFile = useCallback((fileReference: FileReference): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.delete(cacheKey);\n }, []);\n \n const clearCache = useCallback((): void => {\n globalUrlCache.clear();\n }, []);\n \n const getCacheStats = useCallback(() => {\n return {\n size: globalUrlCache.size,\n maxSize: MAX_CACHE_SIZE\n };\n }, []);\n \n return {\n getUrl,\n setUrl,\n getCachedUrl,\n clearFile,\n clearCache,\n getCacheStats\n };\n}\n\n","/**\n * React hook for storage operations\n */\n\nimport { useState, useCallback } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { \n StorageUploadOptions, \n StorageUploadResult, \n StorageFileInfo,\n StorageListOptions,\n StorageListResult,\n uploadFile,\n getPublicUrl,\n getSignedUrl,\n deleteFile,\n listFiles,\n archiveFile\n} from '../utils/storage';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useStorage');\n\nexport interface UseStorageOptions {\n supabase: SupabaseClient;\n appName: string;\n orgId: string;\n}\n\n/**\n * Return value of the useStorage hook.\n * Provides storage operations including upload, URL generation, file management, and listing.\n */\nexport interface UseStorageReturn {\n // Upload\n uploadFile: (file: File, options?: Partial<StorageUploadOptions>) => Promise<StorageUploadResult>;\n isUploading: boolean;\n uploadError: string | null;\n \n // URLs\n getPublicUrl: (path: string) => string;\n getSignedUrl: (path: string, expiresIn?: number) => Promise<string | null>;\n getFileUrl: (path: string) => string; // Alias for getPublicUrl\n \n // File management\n deleteFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n archiveFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n \n // Listing\n listFiles: (options?: Partial<StorageListOptions>) => Promise<StorageListResult>;\n isListing: boolean;\n listError: string | null;\n isLoading: boolean; // Alias for isListing\n error: string | null; // Alias for listError\n \n // State\n files: StorageFileInfo[];\n refreshFiles: () => Promise<void>;\n}\n\n/**\n * Hook for storage operations with app and organisation context\n */\nexport function useStorage({ supabase, appName, orgId }: UseStorageOptions): UseStorageReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n const [isListing, setIsListing] = useState(false);\n const [listError, setListError] = useState<string | null>(null);\n const [files, setFiles] = useState<StorageFileInfo[]>([]);\n\n // Upload file\n const handleUploadFile = useCallback(async (\n file: File, \n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadError(null);\n\n try {\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n if (result.success) {\n // Refresh file list\n await refreshFiles();\n } else {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n }\n }, [supabase, appName, orgId]);\n\n // Get public URL\n const handleGetPublicUrl = useCallback((path: string): string => {\n return getPublicUrl(supabase, path);\n }, [supabase]);\n\n // Get signed URL\n const handleGetSignedUrl = useCallback(async (\n path: string, \n expiresIn?: number\n ): Promise<string | null> => {\n try {\n const result = await getSignedUrl(supabase, path, {\n appName,\n orgId,\n expiresIn\n });\n return result?.url || null;\n } catch (error) {\n log.error('Failed to get signed URL:', error);\n return null;\n }\n }, [supabase, appName, orgId]);\n\n // Delete file\n const handleDeleteFile = useCallback(async (path: string) => {\n try {\n const result = await deleteFile(supabase, path);\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Delete failed'\n };\n }\n }, [supabase]);\n\n // Archive file\n const handleArchiveFile = useCallback(async (path: string) => {\n try {\n const result = await archiveFile(supabase, path, { appName, orgId });\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Archive failed'\n };\n }\n }, [supabase, appName, orgId]);\n\n // List files\n const handleListFiles = useCallback(async (\n options: Partial<StorageListOptions> = {}\n ): Promise<StorageListResult> => {\n setIsListing(true);\n setListError(null);\n\n try {\n const listOptions: StorageListOptions = {\n appName,\n orgId,\n ...options\n };\n\n const result = await listFiles(supabase, listOptions);\n setFiles(result.files);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'List failed';\n setListError(errorMessage);\n return { files: [], totalCount: 0, hasMore: false };\n } finally {\n setIsListing(false);\n }\n }, [supabase, appName, orgId]);\n\n // Refresh files\n const refreshFiles = useCallback(async () => {\n await handleListFiles();\n }, [handleListFiles]);\n\n return {\n // Upload\n uploadFile: handleUploadFile,\n isUploading,\n uploadError,\n \n // URLs\n getPublicUrl: handleGetPublicUrl,\n getSignedUrl: handleGetSignedUrl,\n getFileUrl: handleGetPublicUrl, // Alias for getPublicUrl\n \n // File management\n deleteFile: handleDeleteFile,\n archiveFile: handleArchiveFile,\n \n // Listing\n listFiles: handleListFiles,\n isListing,\n listError,\n isLoading: isListing, // Alias for isListing\n error: listError, // Alias for listError\n \n // State\n files,\n refreshFiles\n };\n}\n\n/**\n * Hook for file upload with progress tracking\n */\nexport function useFileUpload({ supabase, appName, orgId }: UseStorageOptions) {\n const [uploadProgress, setUploadProgress] = useState(0);\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const uploadWithProgress = useCallback(async (\n file: File,\n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadProgress(0);\n setUploadError(null);\n\n try {\n // Simulate progress (Supabase doesn't provide real progress)\n const progressInterval = setInterval(() => {\n setUploadProgress(prev => Math.min(prev + 10, 90));\n }, 100);\n\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n clearInterval(progressInterval);\n setUploadProgress(100);\n\n if (!result.success) {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n setTimeout(() => setUploadProgress(0), 1000);\n }\n }, [supabase, appName, orgId]);\n\n return {\n uploadWithProgress,\n uploadProgress,\n isUploading,\n uploadError\n };\n}\n"],"mappings":"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","names":["useRef","useEffect","useCallback","useEffect","useCallback","useEffect","useState","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useState","useCallback","log","useState","useCallback"]}