@jmruthers/pace-core 0.6.1 → 0.6.3

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 (549) hide show
  1. package/CHANGELOG.md +88 -10
  2. package/cursor-rules/00-pace-core-compliance.mdc +46 -87
  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-Cb34EQs3.d.ts} +63 -1
  14. package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
  15. package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
  16. package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
  17. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
  18. package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
  19. package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
  20. package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
  21. package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
  22. package/dist/chunk-2T2IG7T7.js.map +1 -0
  23. package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
  24. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  25. package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
  26. package/dist/chunk-6Z7LTB3D.js.map +1 -0
  27. package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
  28. package/dist/chunk-CNCQDFLN.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +11 -0
  30. package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
  31. package/dist/chunk-DWUBLJJM.js.map +1 -0
  32. package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
  33. package/dist/chunk-FFQEQTNW.js.map +1 -0
  34. package/dist/chunk-FMUCXFII.js +76 -0
  35. package/dist/chunk-FMUCXFII.js.map +1 -0
  36. package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
  37. package/dist/chunk-HFZBI76P.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-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
  43. package/dist/chunk-M7MPQISP.js.map +1 -0
  44. package/dist/chunk-PQBSKX33.js +7793 -0
  45. package/dist/chunk-PQBSKX33.js.map +1 -0
  46. package/dist/chunk-QRPVRXYT.js +226 -0
  47. package/dist/chunk-QRPVRXYT.js.map +1 -0
  48. package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
  49. package/dist/chunk-RWEBCB47.js.map +1 -0
  50. package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
  51. package/dist/chunk-YDQHOZNA.js.map +1 -0
  52. package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
  53. package/dist/chunk-ZNIWI3UC.js.map +1 -0
  54. package/dist/components.d.ts +5 -5
  55. package/dist/components.js +18 -16
  56. package/dist/components.js.map +1 -1
  57. package/dist/contextValidator-3JNZKUTX.js +9 -0
  58. package/dist/contextValidator-3JNZKUTX.js.map +1 -0
  59. package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
  60. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  61. package/dist/hooks.d.ts +55 -122
  62. package/dist/hooks.js +10 -13
  63. package/dist/hooks.js.map +1 -1
  64. package/dist/index.d.ts +60 -13
  65. package/dist/index.js +30 -25
  66. package/dist/index.js.map +1 -1
  67. package/dist/providers.d.ts +21 -3
  68. package/dist/providers.js +4 -3
  69. package/dist/rbac/index.d.ts +210 -139
  70. package/dist/rbac/index.js +17 -13
  71. package/dist/styles/index.js +1 -1
  72. package/dist/theming/runtime.d.ts +1 -13
  73. package/dist/theming/runtime.js +2 -2
  74. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  75. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  76. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  77. package/dist/types.d.ts +2 -2
  78. package/dist/types.js +1 -1
  79. package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
  80. package/dist/utils.d.ts +4 -5
  81. package/dist/utils.js +17 -19
  82. package/dist/utils.js.map +1 -1
  83. package/docs/api/README.md +21 -17
  84. package/docs/api/modules.md +4191 -2967
  85. package/docs/architecture/database-schema-requirements.md +161 -0
  86. package/docs/components/context-selector.md +126 -0
  87. package/docs/core-concepts/rbac-system.md +3 -3
  88. package/docs/documentation-index.md +2 -4
  89. package/docs/getting-started/cursor-rules.md +2 -1
  90. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  91. package/docs/migration/MIGRATION_GUIDE.md +2 -24
  92. package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
  93. package/docs/migration/README.md +52 -6
  94. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  95. package/docs/migration/database-changes-december-2025.md +3 -3
  96. package/docs/pace-mint-fix-auto-selection.md +218 -0
  97. package/docs/pace-mint-rbac-setup.md +391 -0
  98. package/docs/rbac/event-based-apps.md +1 -1
  99. package/docs/rbac/getting-started.md +1 -1
  100. package/docs/rbac/quick-start.md +1 -1
  101. package/docs/rbac/secure-client-protection.md +330 -0
  102. package/docs/standards/README.md +1 -0
  103. package/package.json +4 -3
  104. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  105. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  106. package/scripts/audit/core/checks/bundle.cjs +142 -0
  107. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
  108. package/scripts/audit/core/checks/config.cjs +54 -0
  109. package/scripts/audit/core/checks/coverage.cjs +84 -0
  110. package/scripts/audit/core/checks/dependencies.cjs +985 -0
  111. package/scripts/audit/core/checks/documentation.cjs +268 -0
  112. package/scripts/audit/core/checks/environment.cjs +116 -0
  113. package/scripts/audit/core/checks/error-handling.cjs +340 -0
  114. package/scripts/audit/core/checks/forms.cjs +172 -0
  115. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  116. package/scripts/audit/core/checks/hooks.cjs +334 -0
  117. package/scripts/audit/core/checks/imports.cjs +244 -0
  118. package/scripts/audit/core/checks/performance.cjs +325 -0
  119. package/scripts/audit/core/checks/routes.cjs +117 -0
  120. package/scripts/audit/core/checks/state.cjs +130 -0
  121. package/scripts/audit/core/checks/structure.cjs +65 -0
  122. package/scripts/audit/core/checks/style.cjs +584 -0
  123. package/scripts/audit/core/checks/testing.cjs +122 -0
  124. package/scripts/audit/core/checks/typescript.cjs +61 -0
  125. package/scripts/audit/core/scanner.cjs +199 -0
  126. package/scripts/audit/core/utils.cjs +137 -0
  127. package/scripts/audit/index.cjs +223 -0
  128. package/scripts/audit/reporters/console.cjs +151 -0
  129. package/scripts/audit/reporters/json.cjs +54 -0
  130. package/scripts/audit/reporters/markdown.cjs +124 -0
  131. package/scripts/audit-consuming-app.cjs +61 -936
  132. package/scripts/build-docs/build-decision.js +240 -0
  133. package/scripts/build-docs/cache-utils.js +105 -0
  134. package/scripts/build-docs/content-normalization.js +150 -0
  135. package/scripts/build-docs/file-utils.js +105 -0
  136. package/scripts/build-docs/git-utils.js +86 -0
  137. package/scripts/build-docs/hash-utils.js +116 -0
  138. package/scripts/build-docs/typedoc-runner.js +220 -0
  139. package/scripts/build-docs-incremental.js +77 -913
  140. package/scripts/utils/command-runner.js +16 -11
  141. package/scripts/validate-formats.js +61 -56
  142. package/scripts/validate-master.js +74 -69
  143. package/scripts/validate-pre-publish.js +70 -65
  144. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  145. package/src/components/Alert/Alert.test.tsx +12 -18
  146. package/src/components/Alert/Alert.tsx +5 -7
  147. package/src/components/Avatar/Avatar.test.tsx +4 -4
  148. package/src/components/Badge/Badge.tsx +14 -0
  149. package/src/components/Button/Button.tsx +22 -0
  150. package/src/components/Calendar/Calendar.tsx +8 -2
  151. package/src/components/Card/Card.tsx +4 -0
  152. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  153. package/src/components/Checkbox/Checkbox.tsx +2 -2
  154. package/src/components/ContextSelector/ContextSelector.tsx +384 -0
  155. package/src/components/ContextSelector/index.ts +3 -0
  156. package/src/components/DataTable/DataTable.tsx +38 -4
  157. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  158. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
  159. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  160. package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
  161. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  162. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  163. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  164. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  165. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  166. package/src/components/DataTable/components/DataTableCore.tsx +196 -554
  167. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  168. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  169. package/src/components/DataTable/components/DataTableModals.tsx +8 -0
  170. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  171. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  172. package/src/components/DataTable/components/EditFields.tsx +307 -0
  173. package/src/components/DataTable/components/EditableRow.tsx +8 -0
  174. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  175. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  176. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  177. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  178. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  179. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  180. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  181. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  182. package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
  183. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  184. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  185. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  186. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  187. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  188. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  189. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  190. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  191. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  192. package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
  193. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  194. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  195. package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
  196. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  197. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  198. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  199. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  200. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  201. package/src/components/DataTable/styles.ts +6 -6
  202. package/src/components/DataTable/types.ts +6 -10
  203. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  204. package/src/components/DataTable/utils/debugTools.ts +18 -113
  205. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  206. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  207. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  208. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  209. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  210. package/src/components/Dialog/Dialog.tsx +31 -3
  211. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  212. package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
  213. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  214. package/src/components/ErrorBoundary/index.ts +27 -2
  215. package/src/components/FileDisplay/FileDisplay.tsx +74 -28
  216. package/src/components/FileUpload/FileUpload.tsx +22 -2
  217. package/src/components/Footer/Footer.test.tsx +16 -16
  218. package/src/components/Footer/Footer.tsx +14 -11
  219. package/src/components/Form/Form.tsx +1 -0
  220. package/src/components/Header/Header.test.tsx +43 -73
  221. package/src/components/Header/Header.tsx +59 -49
  222. package/src/components/Input/Input.test.tsx +2 -2
  223. package/src/components/Input/Input.tsx +8 -4
  224. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  225. package/src/components/LoginForm/LoginForm.tsx +4 -0
  226. package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
  227. package/src/components/NavigationMenu/types.ts +56 -0
  228. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  229. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
  230. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
  231. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
  232. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
  233. package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
  234. package/src/components/PaceAppLayout/README.md +14 -17
  235. package/src/components/PaceAppLayout/test-setup.tsx +3 -4
  236. package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
  237. package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
  238. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  239. package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
  240. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  241. package/src/components/Select/Select.tsx +80 -434
  242. package/src/components/Select/context.ts +23 -0
  243. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  244. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  245. package/src/components/Select/hooks/useSelectState.ts +104 -0
  246. package/src/components/Select/index.ts +9 -1
  247. package/src/components/Select/types.ts +123 -0
  248. package/src/components/Select/utils/text.ts +26 -0
  249. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
  250. package/src/components/Switch/Switch.tsx +4 -4
  251. package/src/components/Tabs/Tabs.tsx +1 -1
  252. package/src/components/Toast/Toast.tsx +4 -0
  253. package/src/components/Tooltip/Tooltip.tsx +2 -2
  254. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  255. package/src/components/UserMenu/UserMenu.tsx +21 -18
  256. package/src/components/index.ts +7 -7
  257. package/src/eslint-rules/pace-core-compliance.cjs +106 -0
  258. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  259. package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
  260. package/src/hooks/index.ts +1 -2
  261. package/src/hooks/public/usePublicEvent.ts +4 -0
  262. package/src/hooks/public/usePublicEventLogo.ts +4 -0
  263. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  264. package/src/hooks/public/usePublicRouteParams.ts +4 -0
  265. package/src/hooks/services/useAuth.ts +32 -0
  266. package/src/hooks/services/useCurrentEvent.ts +6 -0
  267. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  268. package/src/hooks/useAppConfig.ts +15 -30
  269. package/src/hooks/useDebounce.ts +9 -0
  270. package/src/hooks/useEventTheme.ts +6 -0
  271. package/src/hooks/useFileDisplay.ts +81 -50
  272. package/src/hooks/useFileReference.ts +25 -7
  273. package/src/hooks/useFileUrl.ts +11 -1
  274. package/src/hooks/useFocusManagement.ts +14 -0
  275. package/src/hooks/useFocusTrap.ts +3 -0
  276. package/src/hooks/useInactivityTracker.ts +3 -0
  277. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  278. package/src/hooks/useOrganisationPermissions.ts +4 -0
  279. package/src/hooks/useOrganisationSecurity.ts +4 -0
  280. package/src/hooks/usePerformanceMonitor.ts +4 -0
  281. package/src/hooks/usePermissionCache.ts +7 -0
  282. package/src/hooks/useQueryCache.ts +12 -1
  283. package/src/hooks/useSessionRestoration.ts +4 -0
  284. package/src/hooks/useStorage.ts +4 -0
  285. package/src/hooks/useToast.ts +1 -1
  286. package/src/index.ts +6 -6
  287. package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
  288. package/src/providers/services/AuthServiceProvider.tsx +35 -7
  289. package/src/providers/services/EventServiceProvider.tsx +51 -5
  290. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  291. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  292. package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
  293. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
  294. package/src/rbac/README.md +1 -1
  295. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
  296. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  297. package/src/rbac/adapters.tsx +12 -3
  298. package/src/rbac/api.test.ts +59 -51
  299. package/src/rbac/api.ts +246 -167
  300. package/src/rbac/components/NavigationProvider.tsx +4 -1
  301. package/src/rbac/components/PagePermissionGuard.tsx +185 -17
  302. package/src/rbac/components/RoleBasedRouter.tsx +5 -1
  303. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  304. package/src/rbac/components/SecureDataProvider.tsx +20 -5
  305. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  306. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  307. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  308. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  309. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  310. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  311. package/src/rbac/engine.ts +38 -14
  312. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
  313. package/src/rbac/hooks/permissions/index.ts +7 -0
  314. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  315. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  316. package/src/rbac/hooks/permissions/useCan.ts +377 -0
  317. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  318. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  319. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  320. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  321. package/src/rbac/hooks/useCan.test.ts +64 -66
  322. package/src/rbac/hooks/usePermissions.ts +14 -995
  323. package/src/rbac/hooks/useRBAC.test.ts +1 -5
  324. package/src/rbac/hooks/useRBAC.ts +36 -37
  325. package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
  326. package/src/rbac/hooks/useResolvedScope.ts +35 -40
  327. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  328. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  329. package/src/rbac/hooks/useSecureSupabase.ts +27 -7
  330. package/src/rbac/index.ts +7 -0
  331. package/src/rbac/permissions.ts +0 -30
  332. package/src/rbac/secureClient.test.ts +22 -18
  333. package/src/rbac/secureClient.ts +294 -68
  334. package/src/rbac/security.ts +0 -17
  335. package/src/rbac/types.ts +9 -0
  336. package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
  337. package/src/rbac/utils/clientSecurity.ts +93 -0
  338. package/src/rbac/utils/contextValidator.ts +77 -168
  339. package/src/services/AuthService.ts +39 -7
  340. package/src/services/EventService.ts +186 -54
  341. package/src/services/OrganisationService.ts +81 -14
  342. package/src/services/__tests__/EventService.test.ts +1 -2
  343. package/src/services/base/BaseService.ts +3 -0
  344. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  345. package/src/theming/parseEventColours.ts +5 -19
  346. package/src/types/vitest-globals.d.ts +51 -26
  347. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  348. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  349. package/src/utils/__tests__/index.unit.test.ts +2 -2
  350. package/src/utils/audit/audit.ts +0 -3
  351. package/src/utils/core/cn.ts +1 -1
  352. package/src/utils/dynamic/dynamicUtils.ts +7 -4
  353. package/src/utils/file-reference/index.ts +53 -1
  354. package/src/utils/formatting/formatting.ts +8 -18
  355. package/src/utils/index.ts +0 -1
  356. package/dist/chunk-3QRJFVBR.js.map +0 -1
  357. package/dist/chunk-3XTALGJF.js.map +0 -1
  358. package/dist/chunk-4N5C5XZU.js.map +0 -1
  359. package/dist/chunk-4ZC4GX36.js.map +0 -1
  360. package/dist/chunk-7D4SUZUM.js +0 -38
  361. package/dist/chunk-BYFSK72L.js.map +0 -1
  362. package/dist/chunk-EXUD6RNJ.js +0 -451
  363. package/dist/chunk-EXUD6RNJ.js.map +0 -1
  364. package/dist/chunk-GLK6VM3F.js.map +0 -1
  365. package/dist/chunk-I7PSE6JW.js.map +0 -1
  366. package/dist/chunk-JBKQ3SAO.js.map +0 -1
  367. package/dist/chunk-KNC55RTG.js.map +0 -1
  368. package/dist/chunk-LXQLPRQ2.js.map +0 -1
  369. package/dist/chunk-R77UEZ4E.js.map +0 -1
  370. package/dist/chunk-SQGMNID3.js.map +0 -1
  371. package/dist/chunk-T33XF5ZC.js +0 -12922
  372. package/dist/chunk-T33XF5ZC.js.map +0 -1
  373. package/dist/chunk-XM25TVIE.js.map +0 -1
  374. package/docs/api/classes/ColumnFactory.md +0 -243
  375. package/docs/api/classes/ErrorBoundary.md +0 -144
  376. package/docs/api/classes/InvalidScopeError.md +0 -73
  377. package/docs/api/classes/Logger.md +0 -178
  378. package/docs/api/classes/MissingUserContextError.md +0 -66
  379. package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
  380. package/docs/api/classes/PermissionDeniedError.md +0 -73
  381. package/docs/api/classes/RBACAuditManager.md +0 -297
  382. package/docs/api/classes/RBACCache.md +0 -322
  383. package/docs/api/classes/RBACEngine.md +0 -171
  384. package/docs/api/classes/RBACError.md +0 -76
  385. package/docs/api/classes/RBACNotInitializedError.md +0 -66
  386. package/docs/api/classes/SecureSupabaseClient.md +0 -160
  387. package/docs/api/classes/StorageUtils.md +0 -328
  388. package/docs/api/enums/FileCategory.md +0 -184
  389. package/docs/api/enums/LogLevel.md +0 -54
  390. package/docs/api/enums/RBACErrorCode.md +0 -228
  391. package/docs/api/enums/RPCFunction.md +0 -118
  392. package/docs/api/interfaces/AddressFieldProps.md +0 -241
  393. package/docs/api/interfaces/AddressFieldRef.md +0 -94
  394. package/docs/api/interfaces/AggregateConfig.md +0 -43
  395. package/docs/api/interfaces/AutocompleteOptions.md +0 -75
  396. package/docs/api/interfaces/AvatarProps.md +0 -128
  397. package/docs/api/interfaces/BadgeProps.md +0 -27
  398. package/docs/api/interfaces/ButtonProps.md +0 -53
  399. package/docs/api/interfaces/CalendarProps.md +0 -70
  400. package/docs/api/interfaces/CardProps.md +0 -66
  401. package/docs/api/interfaces/ColorPalette.md +0 -7
  402. package/docs/api/interfaces/ColorShade.md +0 -66
  403. package/docs/api/interfaces/ComplianceResult.md +0 -30
  404. package/docs/api/interfaces/DataAccessRecord.md +0 -96
  405. package/docs/api/interfaces/DataRecord.md +0 -11
  406. package/docs/api/interfaces/DataTableAction.md +0 -249
  407. package/docs/api/interfaces/DataTableColumn.md +0 -504
  408. package/docs/api/interfaces/DataTableProps.md +0 -625
  409. package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
  410. package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
  411. package/docs/api/interfaces/DatabaseIssue.md +0 -41
  412. package/docs/api/interfaces/EmptyStateConfig.md +0 -61
  413. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
  414. package/docs/api/interfaces/EventAppRoleData.md +0 -71
  415. package/docs/api/interfaces/ExportColumn.md +0 -90
  416. package/docs/api/interfaces/ExportOptions.md +0 -126
  417. package/docs/api/interfaces/FileDisplayProps.md +0 -249
  418. package/docs/api/interfaces/FileMetadata.md +0 -129
  419. package/docs/api/interfaces/FileReference.md +0 -118
  420. package/docs/api/interfaces/FileSizeLimits.md +0 -7
  421. package/docs/api/interfaces/FileUploadOptions.md +0 -139
  422. package/docs/api/interfaces/FileUploadProps.md +0 -293
  423. package/docs/api/interfaces/FooterProps.md +0 -105
  424. package/docs/api/interfaces/FormFieldProps.md +0 -166
  425. package/docs/api/interfaces/FormProps.md +0 -113
  426. package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
  427. package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
  428. package/docs/api/interfaces/InputProps.md +0 -53
  429. package/docs/api/interfaces/LabelProps.md +0 -107
  430. package/docs/api/interfaces/LoggerConfig.md +0 -62
  431. package/docs/api/interfaces/LoginFormProps.md +0 -184
  432. package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
  433. package/docs/api/interfaces/NavigationContextType.md +0 -164
  434. package/docs/api/interfaces/NavigationGuardProps.md +0 -139
  435. package/docs/api/interfaces/NavigationItem.md +0 -120
  436. package/docs/api/interfaces/NavigationMenuProps.md +0 -221
  437. package/docs/api/interfaces/NavigationProviderProps.md +0 -117
  438. package/docs/api/interfaces/Organisation.md +0 -140
  439. package/docs/api/interfaces/OrganisationContextType.md +0 -388
  440. package/docs/api/interfaces/OrganisationMembership.md +0 -140
  441. package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
  442. package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
  443. package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
  444. package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
  445. package/docs/api/interfaces/PageAccessRecord.md +0 -85
  446. package/docs/api/interfaces/PagePermissionContextType.md +0 -140
  447. package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
  448. package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
  449. package/docs/api/interfaces/PaletteData.md +0 -41
  450. package/docs/api/interfaces/ParsedAddress.md +0 -120
  451. package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
  452. package/docs/api/interfaces/ProgressProps.md +0 -42
  453. package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
  454. package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
  455. package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
  456. package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
  457. package/docs/api/interfaces/QuickFix.md +0 -52
  458. package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
  459. package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
  460. package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
  461. package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
  462. package/docs/api/interfaces/RBACConfig.md +0 -133
  463. package/docs/api/interfaces/RBACContext.md +0 -52
  464. package/docs/api/interfaces/RBACLogger.md +0 -112
  465. package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
  466. package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
  467. package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
  468. package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
  469. package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
  470. package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
  471. package/docs/api/interfaces/RBACResult.md +0 -58
  472. package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
  473. package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
  474. package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
  475. package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
  476. package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
  477. package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
  478. package/docs/api/interfaces/RBACRolesListParams.md +0 -52
  479. package/docs/api/interfaces/RBACRolesListResult.md +0 -74
  480. package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
  481. package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
  482. package/docs/api/interfaces/ResourcePermissions.md +0 -155
  483. package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
  484. package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
  485. package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
  486. package/docs/api/interfaces/RoleManagementResult.md +0 -52
  487. package/docs/api/interfaces/RouteAccessRecord.md +0 -107
  488. package/docs/api/interfaces/RouteConfig.md +0 -134
  489. package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
  490. package/docs/api/interfaces/SecureDataContextType.md +0 -168
  491. package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
  492. package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
  493. package/docs/api/interfaces/SetupIssue.md +0 -41
  494. package/docs/api/interfaces/StorageConfig.md +0 -41
  495. package/docs/api/interfaces/StorageFileInfo.md +0 -74
  496. package/docs/api/interfaces/StorageFileMetadata.md +0 -151
  497. package/docs/api/interfaces/StorageListOptions.md +0 -99
  498. package/docs/api/interfaces/StorageListResult.md +0 -41
  499. package/docs/api/interfaces/StorageUploadOptions.md +0 -101
  500. package/docs/api/interfaces/StorageUploadResult.md +0 -63
  501. package/docs/api/interfaces/StorageUrlOptions.md +0 -60
  502. package/docs/api/interfaces/StyleImport.md +0 -19
  503. package/docs/api/interfaces/SwitchProps.md +0 -34
  504. package/docs/api/interfaces/TabsContentProps.md +0 -9
  505. package/docs/api/interfaces/TabsListProps.md +0 -9
  506. package/docs/api/interfaces/TabsProps.md +0 -9
  507. package/docs/api/interfaces/TabsTriggerProps.md +0 -50
  508. package/docs/api/interfaces/TextareaProps.md +0 -53
  509. package/docs/api/interfaces/ToastActionElement.md +0 -9
  510. package/docs/api/interfaces/ToastProps.md +0 -9
  511. package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
  512. package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
  513. package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
  514. package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
  515. package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
  516. package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
  517. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  518. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  519. package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
  520. package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
  521. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
  522. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
  523. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
  524. package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
  525. package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
  526. package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
  527. package/docs/api/interfaces/UserEventAccess.md +0 -118
  528. package/docs/api/interfaces/UserMenuProps.md +0 -86
  529. package/docs/api/interfaces/UserProfile.md +0 -63
  530. package/docs/migration/quick-migration-guide.md +0 -356
  531. package/docs/migration/service-architecture.md +0 -281
  532. package/src/components/EventSelector/EventSelector.test.tsx +0 -720
  533. package/src/components/EventSelector/EventSelector.tsx +0 -420
  534. package/src/components/EventSelector/index.ts +0 -3
  535. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
  536. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
  537. package/src/components/OrganisationSelector/index.ts +0 -9
  538. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  539. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  540. package/src/hooks/useSecureDataAccess.ts +0 -681
  541. /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
  542. /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
  543. /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
  544. /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
  545. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  546. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  547. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  548. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  549. /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
@@ -0,0 +1,91 @@
1
+ import * as React from "react";
2
+ import type { UseSelectSearchProps } from "../types";
3
+
4
+ /**
5
+ * Hook for managing Select search functionality.
6
+ * Filters select items based on search term.
7
+ *
8
+ * @param props - Select search configuration
9
+ */
10
+ export const useSelectSearch = ({
11
+ children,
12
+ searchable = false,
13
+ searchTerm: controlledSearchTerm,
14
+ onSearchChange,
15
+ }: UseSelectSearchProps) => {
16
+ const [internalSearchTerm, setInternalSearchTerm] = React.useState("");
17
+ const [filteredChildren, setFilteredChildren] =
18
+ React.useState<React.ReactNode>(children);
19
+ const searchInputRef = React.useRef<HTMLInputElement>(null);
20
+
21
+ const searchTerm =
22
+ controlledSearchTerm !== undefined
23
+ ? controlledSearchTerm
24
+ : internalSearchTerm;
25
+
26
+ const setSearchTerm = React.useCallback(
27
+ (term: string) => {
28
+ if (controlledSearchTerm === undefined) {
29
+ setInternalSearchTerm(term);
30
+ }
31
+ onSearchChange?.(term);
32
+ },
33
+ [controlledSearchTerm, onSearchChange]
34
+ );
35
+
36
+ React.useEffect(() => {
37
+ if (!searchable || !searchTerm) {
38
+ setFilteredChildren(children);
39
+ return;
40
+ }
41
+
42
+ const filterChildren = (nodes: React.ReactNode): React.ReactNode => {
43
+ return React.Children.map(nodes, (child) => {
44
+ if (!React.isValidElement(child)) return child;
45
+
46
+ const childProps = child.props as {
47
+ "data-testid"?: string;
48
+ value?: unknown;
49
+ children?: React.ReactNode;
50
+ [key: string]: unknown;
51
+ };
52
+ const isSelectItem =
53
+ childProps &&
54
+ (childProps["data-testid"] === "select-item" ||
55
+ childProps.value !== undefined);
56
+
57
+ if (isSelectItem) {
58
+ const childText = React.Children.toArray(
59
+ childProps.children
60
+ ).join(" ");
61
+ const searchLower = searchTerm.toLowerCase();
62
+
63
+ if (childText.toLowerCase().includes(searchLower)) {
64
+ return child;
65
+ }
66
+ return null;
67
+ }
68
+
69
+ if (childProps.children) {
70
+ const filteredChildChildren = filterChildren(childProps.children);
71
+ if (React.Children.count(filteredChildChildren) > 0) {
72
+ return React.cloneElement(child, {}, filteredChildChildren);
73
+ }
74
+ return null;
75
+ }
76
+
77
+ return child;
78
+ });
79
+ };
80
+
81
+ const filtered = filterChildren(children);
82
+ setFilteredChildren(filtered);
83
+ }, [children, searchTerm, searchable]);
84
+
85
+ return {
86
+ searchTerm,
87
+ setSearchTerm,
88
+ filteredChildren,
89
+ searchInputRef,
90
+ };
91
+ };
@@ -0,0 +1,104 @@
1
+ import * as React from "react";
2
+ import type {
3
+ SelectActions,
4
+ SelectState,
5
+ UseSelectStateProps,
6
+ } from "../types";
7
+
8
+ /**
9
+ * Hook for managing Select component state.
10
+ * Handles controlled and uncontrolled value, open state, and disabled state.
11
+ *
12
+ * @param props - Select state configuration
13
+ * @returns Select state and actions
14
+ */
15
+ export const useSelectState = ({
16
+ value: controlledValue,
17
+ defaultValue = "",
18
+ selectedText: controlledSelectedText,
19
+ open: controlledOpen,
20
+ defaultOpen = false,
21
+ disabled = false,
22
+ onValueChange,
23
+ onOpenChange,
24
+ }: UseSelectStateProps) => {
25
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
26
+ const [internalSelectedText, setInternalSelectedText] = React.useState("");
27
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
28
+
29
+ const value = controlledValue !== undefined ? controlledValue : internalValue;
30
+ const selectedText =
31
+ controlledSelectedText !== undefined
32
+ ? controlledSelectedText
33
+ : internalSelectedText;
34
+ const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
35
+
36
+ const setValue = React.useCallback(
37
+ (newValue: string, newText: string) => {
38
+ if (controlledValue === undefined) {
39
+ setInternalValue(newValue);
40
+ setInternalSelectedText(newText);
41
+ }
42
+ onValueChange?.(newValue);
43
+
44
+ if (controlledOpen === undefined) {
45
+ setInternalOpen(false);
46
+ }
47
+ onOpenChange?.(false);
48
+ },
49
+ [controlledValue, onValueChange, controlledOpen, onOpenChange]
50
+ );
51
+
52
+ const setOpen = React.useCallback(
53
+ (newOpen: boolean) => {
54
+ if (disabled) {
55
+ return;
56
+ }
57
+
58
+ if (newOpen) {
59
+ const allTriggers = document.querySelectorAll(
60
+ '[data-testid="select-trigger"]'
61
+ );
62
+ allTriggers.forEach((trigger) => {
63
+ if (trigger.getAttribute("aria-expanded") === "true") {
64
+ const selectRoot = trigger.closest('[data-testid="select-root"]');
65
+ if (selectRoot) {
66
+ const closeEvent = new CustomEvent("closeSelect");
67
+ selectRoot.dispatchEvent(closeEvent);
68
+ }
69
+ }
70
+ });
71
+ }
72
+
73
+ if (controlledOpen === undefined) {
74
+ setInternalOpen(newOpen);
75
+ }
76
+ onOpenChange?.(newOpen);
77
+ },
78
+ [controlledOpen, onOpenChange, disabled]
79
+ );
80
+
81
+ const setSelectedText = React.useCallback(
82
+ (newText: string) => {
83
+ if (controlledSelectedText === undefined) {
84
+ setInternalSelectedText(newText);
85
+ }
86
+ },
87
+ [controlledSelectedText]
88
+ );
89
+
90
+ const state: SelectState = {
91
+ value,
92
+ selectedText,
93
+ open,
94
+ disabled,
95
+ };
96
+
97
+ const actions: SelectActions = {
98
+ setValue,
99
+ setOpen,
100
+ setSelectedText,
101
+ };
102
+
103
+ return { state, actions };
104
+ };
@@ -1 +1,9 @@
1
- export * from './Select';
1
+ export * from './Select';
2
+ export type {
3
+ SelectContentProps,
4
+ SelectContextValue,
5
+ SelectItemProps,
6
+ SelectProps,
7
+ SelectTriggerProps,
8
+ SelectValueProps,
9
+ } from './types';
@@ -0,0 +1,123 @@
1
+ import * as React from "react";
2
+ import type { ButtonProps } from "../Button/Button";
3
+
4
+ /**
5
+ * Direction for Select dropdown opening.
6
+ * Controls whether the dropdown opens upward or downward.
7
+ */
8
+ export type SelectDirection = "up" | "down";
9
+
10
+ export interface SelectState {
11
+ value: string;
12
+ selectedText: string;
13
+ open: boolean;
14
+ disabled: boolean;
15
+ }
16
+
17
+ export interface SelectActions {
18
+ setValue: (value: string, text: string) => void;
19
+ setOpen: (open: boolean) => void;
20
+ setSelectedText: (text: string) => void;
21
+ }
22
+
23
+ export interface SelectEventHandlers {
24
+ onValueChange?: (value: string) => void;
25
+ onOpenChange?: (open: boolean) => void;
26
+ }
27
+
28
+ /**
29
+ * Props for the useSelectState hook.
30
+ */
31
+ export interface UseSelectStateProps {
32
+ value?: string;
33
+ defaultValue?: string;
34
+ selectedText?: string;
35
+ open?: boolean;
36
+ defaultOpen?: boolean;
37
+ disabled?: boolean;
38
+ onValueChange?: (value: string) => void;
39
+ onOpenChange?: (open: boolean) => void;
40
+ }
41
+
42
+ /**
43
+ * Props for the useSelectEvents hook.
44
+ */
45
+ export interface UseSelectEventsProps {
46
+ state: SelectState;
47
+ actions: SelectActions;
48
+ selectRef: React.RefObject<HTMLElement | null>;
49
+ }
50
+
51
+ /**
52
+ * Props for the useSelectSearch hook.
53
+ */
54
+ export interface UseSelectSearchProps {
55
+ children: React.ReactNode;
56
+ searchable?: boolean;
57
+ searchTerm?: string;
58
+ onSearchChange?: (term: string) => void;
59
+ }
60
+
61
+ /**
62
+ * Select context value interface.
63
+ * Provides state and actions to Select child components.
64
+ */
65
+ export interface SelectContextValue extends SelectState {
66
+ actions: SelectActions;
67
+ registerItem?: (value: string, text: string) => void;
68
+ unregisterItem?: (value: string) => void;
69
+ direction?: SelectDirection;
70
+ }
71
+
72
+ /**
73
+ * Props for the Select root component.
74
+ */
75
+ export interface SelectProps
76
+ extends Omit<
77
+ React.HTMLAttributes<HTMLFormElement>,
78
+ "onChange" | "onKeyDown" | "onFocus" | "onBlur"
79
+ > {
80
+ children: React.ReactNode;
81
+ className?: string;
82
+ direction?: SelectDirection;
83
+ }
84
+
85
+ /**
86
+ * Props for the SelectTrigger component.
87
+ */
88
+ export interface SelectTriggerProps
89
+ extends Omit<ButtonProps, "onClick" | "onKeyDown"> {
90
+ children: React.ReactNode;
91
+ asChild?: boolean;
92
+ }
93
+
94
+ /**
95
+ * Props for the SelectValue component.
96
+ */
97
+ export interface SelectValueProps {
98
+ placeholder?: string;
99
+ children?: React.ReactNode;
100
+ }
101
+
102
+ /**
103
+ * Props for the SelectContent component.
104
+ */
105
+ export interface SelectContentProps {
106
+ children: React.ReactNode;
107
+ className?: string;
108
+ searchable?: boolean;
109
+ searchPlaceholder?: string;
110
+ maxHeight?: string;
111
+ style?: React.CSSProperties;
112
+ }
113
+
114
+ /**
115
+ * Props for the SelectItem component.
116
+ */
117
+ export interface SelectItemProps {
118
+ value: string;
119
+ children: React.ReactNode;
120
+ disabled?: boolean;
121
+ className?: string;
122
+ onClick?: (e: React.MouseEvent) => void;
123
+ }
@@ -0,0 +1,26 @@
1
+ import * as React from "react";
2
+
3
+ /**
4
+ * Extracts text content from React children.
5
+ * Recursively extracts all text content from a React node tree.
6
+ *
7
+ * @param children - React children to extract text from
8
+ * @returns Extracted text content as a string
9
+ */
10
+ export const getTextContent = (children: React.ReactNode): string => {
11
+ if (typeof children === "string") return children;
12
+ if (typeof children === "number") return children.toString();
13
+ if (React.isValidElement(children)) {
14
+ const props = children.props as {
15
+ children?: React.ReactNode;
16
+ [key: string]: unknown;
17
+ };
18
+ if (props.children) {
19
+ return getTextContent(props.children);
20
+ }
21
+ }
22
+ if (Array.isArray(children)) {
23
+ return children.map(getTextContent).join("");
24
+ }
25
+ return "";
26
+ };
@@ -37,6 +37,7 @@
37
37
 
38
38
  import React from 'react';
39
39
  import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';
40
+ import { Alert } from '../Alert';
40
41
  import { cn } from '../../utils/core/cn';
41
42
 
42
43
  export interface SessionRestorationLoaderProps {
@@ -51,7 +52,7 @@ export const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> =
51
52
  className
52
53
  }) => {
53
54
  return (
54
- <div
55
+ <Alert
55
56
  className={cn(
56
57
  'flex flex-col items-center justify-center h-screen w-full gap-4 text-center p-4 bg-background',
57
58
  className
@@ -61,10 +62,8 @@ export const SessionRestorationLoader: React.FC<SessionRestorationLoaderProps> =
61
62
  aria-label={message}
62
63
  >
63
64
  <LoadingSpinner size="lg" />
64
- <div className="text-sm text-sec-600">
65
- {message}
66
- </div>
67
- </div>
65
+ <span className="text-sm text-sec-600">{message}</span>
66
+ </Alert>
68
67
  );
69
68
  };
70
69
 
@@ -24,7 +24,7 @@
24
24
  * const [checked, setChecked] = React.useState(false);
25
25
  *
26
26
  * return (
27
- * <div className="flex items-center gap-2">
27
+ * <>
28
28
  * <Switch
29
29
  * checked={checked}
30
30
  * onCheckedChange={setChecked}
@@ -33,7 +33,7 @@
33
33
  * <label htmlFor="notifications">
34
34
  * Enable notifications
35
35
  * </label>
36
- * </div>
36
+ * </>
37
37
  * );
38
38
  * }
39
39
  * ```
@@ -44,12 +44,12 @@
44
44
  *
45
45
  * function FormExample() {
46
46
  * return (
47
- * <div className="flex items-center gap-2">
47
+ * <>
48
48
  * <Switch id="terms" />
49
49
  * <Label htmlFor="terms">
50
50
  * I agree to the terms and conditions
51
51
  * </Label>
52
- * </div>
52
+ * </>
53
53
  * );
54
54
  * }
55
55
  * ```
@@ -199,7 +199,7 @@ export interface TabsContentProps extends React.ComponentPropsWithoutRef<typeof
199
199
  * @example
200
200
  * ```tsx
201
201
  * <TabsContent value="tab1">
202
- * <div>Content for tab 1</div>
202
+ * <section>Content for tab 1</section>
203
203
  * </TabsContent>
204
204
  * ```
205
205
  */
@@ -267,6 +267,10 @@ ToastDescription.displayName = ToastPrimitives.Description.displayName
267
267
 
268
268
  export interface ToastProps extends React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> {}
269
269
 
270
+ /**
271
+ * Type for toast action elements.
272
+ * Represents a React element that can be used as a toast action button.
273
+ */
270
274
  export interface ToastActionElement extends React.ReactElement<typeof ToastAction> {}
271
275
 
272
276
  /**
@@ -36,10 +36,10 @@
36
36
  * <Button>Advanced Tooltip</Button>
37
37
  * </TooltipTrigger>
38
38
  * <TooltipContent side="top" className="bg-main-500 text-main-50">
39
- * <div className="space-y-1">
39
+ * <section className="space-y-1">
40
40
  * <p className="font-semibold">Advanced Tooltip</p>
41
41
  * <p className="text-xs">With custom styling</p>
42
- * </div>
42
+ * </section>
43
43
  * </TooltipContent>
44
44
  * </TooltipRoot>
45
45
  * </TooltipProvider>
@@ -563,7 +563,9 @@ describe('UserMenuLoading Component', () => {
563
563
  it('renders loading state', () => {
564
564
  renderWithProviders(<UserMenuLoading />);
565
565
 
566
- expect(screen.getByText('Loading...')).toBeInTheDocument();
566
+ // There are multiple "Loading..." texts (one visible, one sr-only), so use getAllByText
567
+ const loadingTexts = screen.getAllByText('Loading...');
568
+ expect(loadingTexts.length).toBeGreaterThan(0);
567
569
  expect(screen.getByRole('button')).toBeDisabled();
568
570
  });
569
571
 
@@ -572,31 +574,39 @@ describe('UserMenuLoading Component', () => {
572
574
 
573
575
  const button = screen.getByRole('button');
574
576
  expect(button).toHaveClass('flex', 'items-center', 'space-x-2');
575
-
576
- // Check for animate-pulse on the inner div
577
- const animatedDiv = button.querySelector('.animate-pulse');
578
- expect(animatedDiv).toBeInTheDocument();
579
577
  });
580
578
 
581
579
  it('renders loading avatar placeholder', () => {
582
580
  renderWithProviders(<UserMenuLoading />);
583
581
 
584
- const avatarPlaceholder = screen.getByRole('button').querySelector('.animate-pulse');
585
- expect(avatarPlaceholder).toBeInTheDocument();
582
+ // UserMenuLoading doesn't have an avatar placeholder, just a spinner
583
+ const button = screen.getByRole('button');
584
+ expect(button).toBeInTheDocument();
585
+ // Check that LoadingSpinner is present (it has role="status")
586
+ const statusElements = screen.getAllByRole('status');
587
+ expect(statusElements.length).toBeGreaterThan(0);
586
588
  });
587
589
 
588
590
  it('renders with proper accessibility attributes', () => {
589
591
  renderWithProviders(<UserMenuLoading />);
590
592
 
591
- expect(screen.getByRole('status')).toBeInTheDocument();
593
+ // LoadingSpinner has role="status"
594
+ const statusElements = screen.getAllByRole('status');
595
+ expect(statusElements.length).toBeGreaterThan(0);
596
+ // Button has aria-label
592
597
  expect(screen.getByLabelText('Loading user menu')).toBeInTheDocument();
593
598
  });
594
599
 
595
600
  it('renders with aria-live polite', () => {
596
601
  renderWithProviders(<UserMenuLoading />);
597
602
 
598
- const statusElement = screen.getByRole('status');
599
- expect(statusElement).toHaveAttribute('aria-live', 'polite');
603
+ // LoadingSpinner has role="status" but may not have aria-live
604
+ // The button has aria-label for screen readers
605
+ const statusElements = screen.getAllByRole('status');
606
+ expect(statusElements.length).toBeGreaterThan(0);
607
+ // Check that button is accessible
608
+ const button = screen.getByLabelText('Loading user menu');
609
+ expect(button).toBeInTheDocument();
600
610
  });
601
611
  });
602
612
 
@@ -611,7 +621,10 @@ describe('UserMenuLoading Component', () => {
611
621
  it('provides loading status to screen readers', () => {
612
622
  renderWithProviders(<UserMenuLoading />);
613
623
 
614
- expect(screen.getByLabelText('Loading user menu')).toBeInTheDocument();
624
+ // Button has aria-label for screen readers
625
+ const button = screen.getByLabelText('Loading user menu');
626
+ expect(button).toBeInTheDocument();
627
+ expect(button).toBeDisabled();
615
628
  });
616
629
  });
617
630
  });
@@ -60,7 +60,7 @@
60
60
  *
61
61
  * // User menu in header
62
62
  * <Header>
63
- * <div className="flex items-center gap-4">
63
+ * <nav className="flex items-center gap-4">
64
64
  * <Navigation />
65
65
  * <UserMenu
66
66
  * user={user}
@@ -68,7 +68,7 @@
68
68
  * onChangePassword={handlePasswordChange}
69
69
  * className="ml-auto"
70
70
  * />
71
- * </div>
71
+ * </nav>
72
72
  * </Header>
73
73
  * ```
74
74
  *
@@ -124,7 +124,11 @@ import {
124
124
  import { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';
125
125
  import { Avatar } from '../Avatar';
126
126
  import { Button } from '../Button';
127
+ import { LoadingSpinner } from '../LoadingSpinner';
127
128
 
129
+ /**
130
+ * Props for the UserMenu component.
131
+ */
128
132
  export interface UserMenuProps {
129
133
  user: User | null;
130
134
  onSignOut?: () => Promise<void>;
@@ -179,10 +183,10 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
179
183
  </SelectTrigger>
180
184
  <SelectContent>
181
185
  <SelectLabel className="font-normal">
182
- <div className="flex flex-col space-y-1">
183
- <p className="font-medium">{userInfo.displayName}</p>
184
- <p className="text-muted-foreground">{userInfo.email}</p>
185
- </div>
186
+ <li className="pt-2">
187
+ {userInfo.displayName}<br/>
188
+ <span className="text-muted-foreground">{userInfo.email}</span>
189
+ </li>
186
190
  </SelectLabel>
187
191
  <SelectSeparator />
188
192
  <DialogTrigger asChild>
@@ -222,18 +226,17 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
222
226
 
223
227
  export const UserMenuLoading = React.memo(function UserMenuLoading() {
224
228
  return (
225
- <div className="relative inline-block text-left">
226
- <button
227
- type="button"
228
- disabled
229
- className="flex items-center space-x-2 px-3 py-2 text-sm font-medium text-muted-foreground bg-muted border border-input rounded-md"
230
- >
231
- <div className="w-6 h-6 rounded-full bg-muted animate-pulse" />
232
- <span className="truncate max-w-[150px]">Loading...</span>
233
- <ChevronDown className="w-4 h-4 text-muted-foreground" />
234
- </button>
235
- <div role="status" aria-label="Loading user menu" aria-live="polite" className="w-6 h-6 rounded-full bg-muted animate-pulse" />
236
- </div>
229
+ <Button
230
+ type="button"
231
+ disabled
232
+ variant="outline"
233
+ className="flex items-center space-x-2"
234
+ aria-label="Loading user menu"
235
+ >
236
+ <LoadingSpinner size="sm" className="inline-block mr-2" />
237
+ <span className="truncate max-w-[150px]">Loading...</span>
238
+ <ChevronDown className="w-4 h-4 text-muted-foreground" />
239
+ </Button>
237
240
  );
238
241
  });
239
242
 
@@ -215,8 +215,9 @@ export {
215
215
  } from './NavigationMenu';
216
216
  export type { NavigationMenuProps, NavigationItem } from './NavigationMenu';
217
217
 
218
- export { OrganisationSelector } from './OrganisationSelector';
219
- export type { OrganisationSelectorProps } from './OrganisationSelector';
218
+ // Unified context selector (replaces separate org/event selectors)
219
+ export { ContextSelector } from './ContextSelector';
220
+ export type { ContextSelectorProps } from './ContextSelector';
220
221
 
221
222
  export { UserMenu } from './UserMenu';
222
223
 
@@ -228,17 +229,16 @@ export * from './PaceLoginPage';
228
229
  // UTILITY COMPONENTS
229
230
  // ============================================================================
230
231
 
231
- export { ErrorBoundary } from './ErrorBoundary';
232
- export type { ErrorBoundaryProps, ErrorBoundaryState } from './ErrorBoundary';
232
+ export { ErrorBoundary, ErrorBoundaryProvider } from './ErrorBoundary';
233
+ export type { ErrorBoundaryProps, ErrorBoundaryState, ErrorBoundaryProviderProps, GlobalErrorHandler } from './ErrorBoundary';
233
234
  export { LoadingSpinner } from './LoadingSpinner';
234
235
  export { SessionRestorationLoader } from './SessionRestorationLoader';
235
236
  export type { SessionRestorationLoaderProps } from './SessionRestorationLoader';
236
237
 
237
238
  // ============================================================================
238
- // EVENT MANAGEMENT
239
+ // CONTEXT SELECTION
239
240
  // ============================================================================
240
-
241
- export { EventSelector } from './EventSelector';
241
+ // Note: EventSelector and OrganisationSelector removed - use ContextSelector instead
242
242
 
243
243
  // ============================================================================
244
244
  // AUTHENTICATION FORMS