@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -40,20 +40,21 @@ import { getTextContent } from "./utils/text";
40
40
  * Provides select dropdown functionality with search, keyboard navigation, and accessibility.
41
41
  *
42
42
  * @param props - Select configuration
43
- * @param ref - Forwarded ref to the form element
43
+ * @param ref - Forwarded ref to the fieldset element
44
44
  * @returns The rendered select component
45
45
  */
46
- export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectStateProps>(
47
- ({
46
+ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSelectStateProps>(
47
+ ({
48
48
  children,
49
49
  className,
50
50
  direction = 'down',
51
+ showCheckmark = true,
51
52
  ...selectProps
52
53
  }, ref) => {
53
- const internalRef = React.useRef<HTMLFormElement>(null);
54
+ const internalRef = React.useRef<HTMLFieldSetElement>(null);
54
55
  const selectRef = React.useMemo(() => {
55
56
  if (ref && typeof ref === 'object' && 'current' in ref) {
56
- return ref as React.RefObject<HTMLFormElement | null>;
57
+ return ref as React.RefObject<HTMLFieldSetElement | null>;
57
58
  }
58
59
  return internalRef;
59
60
  }, [ref]);
@@ -108,7 +109,7 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
108
109
  // Query the DOM for the SelectItem (li element) with matching value
109
110
  // Must be a select-item, not the trigger which also has data-value
110
111
  let selectItem = selectElement.querySelector(`[data-testid="select-item"][data-value="${state.value}"]`) as HTMLElement;
111
-
112
+
112
113
  // If not found, try querying within content containers
113
114
  if (!selectItem) {
114
115
  const hiddenContent = selectElement.querySelector('[data-testid="select-content-hidden"]');
@@ -116,7 +117,7 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
116
117
  selectItem = hiddenContent.querySelector(`[data-testid="select-item"][data-value="${state.value}"]`) as HTMLElement;
117
118
  }
118
119
  }
119
-
120
+
120
121
  // Try visible content as fallback
121
122
  if (!selectItem) {
122
123
  const visibleContent = selectElement.querySelector('[data-testid="select-content"]');
@@ -130,7 +131,7 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
130
131
  let textContent = selectItem.textContent?.trim() || '';
131
132
  // Remove any check mark icons or other decorators (basic cleanup)
132
133
  textContent = textContent.split('\n').map(line => line.trim()).filter(line => line).join(' ');
133
-
134
+
134
135
  if (textContent) {
135
136
  actions.setSelectedText(textContent);
136
137
  // Also register it for future use
@@ -138,11 +139,11 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
138
139
  return;
139
140
  }
140
141
  }
141
-
142
+
142
143
  // If not found and we have a content container, items might still be rendering
143
144
  // Don't clear selectedText in this case - let the MutationObserver or retry effect handle it
144
- const hasContentContainer = selectElement.querySelector('[data-testid="select-content-hidden"]') ||
145
- selectElement.querySelector('[data-testid="select-content"]');
145
+ const hasContentContainer = selectElement.querySelector('[data-testid="select-content-hidden"]') ||
146
+ selectElement.querySelector('[data-testid="select-content"]');
146
147
  if (!hasContentContainer) {
147
148
  // No content container means no items exist - clear selectedText
148
149
  actions.setSelectedText('');
@@ -198,23 +199,20 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
198
199
  registerItem,
199
200
  unregisterItem,
200
201
  direction,
201
- }), [state, actions, registerItem, unregisterItem, direction]);
202
+ showCheckmark,
203
+ }), [state, actions, registerItem, unregisterItem, direction, showCheckmark]);
202
204
 
203
205
  return (
204
- <form
206
+ <fieldset
205
207
  ref={selectRef}
206
- className={cn("relative", className)}
208
+ className={cn("relative border-0 p-0 m-0", className)}
207
209
  data-value={state.value}
208
210
  data-testid="select-root"
209
- onSubmit={(e) => {
210
- e.preventDefault();
211
- e.stopPropagation();
212
- }}
213
211
  >
214
212
  <SelectContext.Provider value={contextValue}>
215
213
  {children}
216
214
  </SelectContext.Provider>
217
- </form>
215
+ </fieldset>
218
216
  );
219
217
  }
220
218
  );
@@ -239,14 +237,14 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
239
237
 
240
238
  // Use ref to store the latest handleClick to avoid re-creating the effect
241
239
  const handleClickRef = React.useRef<(e: React.MouseEvent) => void>(undefined);
242
-
240
+
243
241
  const handleClick = React.useCallback((e: React.MouseEvent) => {
244
242
  if (disabled) {
245
243
  e.preventDefault();
246
244
  e.stopPropagation();
247
245
  return;
248
246
  }
249
-
247
+
250
248
  e.preventDefault();
251
249
  e.stopPropagation();
252
250
  actions.setOpen(!open);
@@ -304,15 +302,27 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
304
302
  ...props
305
303
  };
306
304
 
305
+ // Call all hooks unconditionally at the top level
306
+ // Hooks must be called in the same order on every render
307
+ // Simple ref forwarding - must be called before any early returns
308
+ const handleRef = React.useCallback((node: HTMLButtonElement | null) => {
309
+ if (typeof ref === 'function') {
310
+ ref(node);
311
+ } else if (ref) {
312
+ (ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
313
+ }
314
+ }, [ref]);
315
+
316
+ // Early return after all hooks have been called
307
317
  if (asChild) {
308
- const childElement = children as React.ReactElement<{ children?: React.ReactNode; [key: string]: unknown }>;
318
+ const childElement = children as React.ReactElement<{ children?: React.ReactNode;[key: string]: unknown }>;
309
319
  const childChildren = React.Children.toArray(childElement.props.children);
310
320
  const hasChevron = childChildren.some(child => {
311
321
  if (React.isValidElement(child)) {
312
- const childProps = child.props as { 'data-testid'?: string; [key: string]: unknown };
313
- return child.type === ChevronDown ||
314
- (child.type === 'svg' && childProps['data-testid'] === 'chevron-down') ||
315
- (typeof child === 'object' && 'type' in child && typeof child.type === 'function' && child.type.name === 'ChevronDown');
322
+ const childProps = child.props as { 'data-testid'?: string;[key: string]: unknown };
323
+ return child.type === ChevronDown ||
324
+ (child.type === 'svg' && childProps['data-testid'] === 'chevron-down') ||
325
+ (typeof child === 'object' && 'type' in child && typeof child.type === 'function' && child.type.name === 'ChevronDown');
316
326
  }
317
327
  return false;
318
328
  });
@@ -329,27 +339,17 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
329
339
  className: mergedClassName,
330
340
  children: hasChevron ? childChildren : [
331
341
  ...childChildren,
332
- <ChevronDown
342
+ <ChevronDown
333
343
  key="chevron-down"
334
344
  className={cn(
335
345
  "size-4 opacity-50 transition-transform pointer-events-none float-right",
336
346
  open && "rotate-180"
337
- )}
347
+ )}
338
348
  />
339
349
  ]
340
350
  });
341
351
  }
342
352
 
343
-
344
- // Simple ref forwarding
345
- const handleRef = React.useCallback((node: HTMLButtonElement | null) => {
346
- if (typeof ref === 'function') {
347
- ref(node);
348
- } else if (ref) {
349
- (ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
350
- }
351
- }, [ref]);
352
-
353
353
  return (
354
354
  <Button
355
355
  ref={handleRef}
@@ -382,11 +382,11 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
382
382
  {...props}
383
383
  >
384
384
  {children}
385
- <ChevronDown
385
+ <ChevronDown
386
386
  className={cn(
387
387
  "size-4 opacity-50 transition-transform pointer-events-none float-right",
388
388
  open && "rotate-180"
389
- )}
389
+ )}
390
390
  />
391
391
  </Button>
392
392
  );
@@ -411,8 +411,8 @@ export const SelectValue = React.forwardRef<HTMLSpanElement, SelectValueProps>(
411
411
  const { selectedText } = useSelectContext();
412
412
 
413
413
  return (
414
- <span
415
- ref={ref}
414
+ <span
415
+ ref={ref}
416
416
  data-testid="select-value"
417
417
  style={{ pointerEvents: 'none' }}
418
418
  className="pointer-events-none"
@@ -437,9 +437,9 @@ SelectValue.displayName = "SelectValue";
437
437
  * @returns The rendered select content
438
438
  */
439
439
  export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentProps>(
440
- ({
441
- children,
442
- className,
440
+ ({
441
+ children,
442
+ className,
443
443
  searchable = false,
444
444
  searchPlaceholder = "Search...",
445
445
  maxHeight = "max(20rem, 50vh)",
@@ -475,19 +475,19 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
475
475
  }
476
476
 
477
477
  const opensUpward = direction === 'up';
478
-
478
+
479
479
  return (
480
480
  <ul
481
481
  ref={ref}
482
482
  className={cn(
483
483
  "absolute z-[99999] w-full overflow-y-auto border border-main-300 bg-main-50 shadow-lg",
484
484
  "list-none p-0 m-0",
485
- opensUpward
486
- ? "rounded-t-md border-b-0"
485
+ opensUpward
486
+ ? "rounded-t-md border-b-0"
487
487
  : "rounded-b-md border-t-0",
488
488
  className
489
489
  )}
490
- style={{
490
+ style={{
491
491
  [opensUpward ? 'bottom' : 'top']: '100%',
492
492
  left: 0,
493
493
  right: 0,
@@ -500,38 +500,36 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
500
500
  role="listbox"
501
501
  >
502
502
  {searchable && (
503
- <div className="p-2 border-b border-main-200">
504
- <div className="relative">
505
- <Search className="absolute left-2 top-1/2 transform -translate-y-1/2 size-4 text-main-400" />
506
- <input
507
- ref={searchInputRef}
508
- type="text"
509
- placeholder={searchPlaceholder}
510
- value={searchTerm}
511
- onChange={(e) => setSearchTerm(e.target.value)}
512
- onKeyDown={(e) => {
513
- if (e.key === 'Escape') {
514
- e.preventDefault();
515
- setSearchTerm('');
516
- }
517
- }}
518
- className="w-full pl-8 pr-8 py-1 text-sm border border-main-200 rounded focus:outline-none focus:ring-2 focus:ring-main-500"
519
- data-testid="select-search-input"
520
- aria-label="Search options"
521
- />
522
- {searchTerm && (
523
- <button
524
- type="button"
525
- onClick={() => setSearchTerm('')}
526
- className="absolute right-2 top-1/2 transform -translate-y-1/2 text-main-400 hover:text-main-600"
527
- data-testid="select-clear-search"
528
- aria-label="Clear search"
529
- >
530
- <X className="size-4" />
531
- </button>
532
- )}
533
- </div>
534
- </div>
503
+ <li className="relative p-2 border-b border-main-200 sticky top-0 bg-main-50 z-10" data-testid="select-search-item">
504
+ <Search className="absolute left-2 top-1/2 transform -translate-y-1/2 size-4 text-main-400" />
505
+ <input
506
+ ref={searchInputRef}
507
+ type="text"
508
+ placeholder={searchPlaceholder}
509
+ value={searchTerm}
510
+ onChange={(e) => setSearchTerm(e.target.value)}
511
+ onKeyDown={(e) => {
512
+ if (e.key === 'Escape') {
513
+ e.preventDefault();
514
+ setSearchTerm('');
515
+ }
516
+ }}
517
+ className="w-full pl-8 pr-8 py-1 text-sm border border-main-200 rounded focus:outline-none focus:ring-2 focus:ring-main-500"
518
+ data-testid="select-search-input"
519
+ aria-label="Search options"
520
+ />
521
+ {searchTerm && (
522
+ <button
523
+ type="button"
524
+ onClick={() => setSearchTerm('')}
525
+ className="absolute right-2 top-1/2 transform -translate-y-1/2 text-main-400 hover:text-main-600"
526
+ data-testid="select-clear-search"
527
+ aria-label="Clear search"
528
+ >
529
+ <X className="size-4" />
530
+ </button>
531
+ )}
532
+ </li>
535
533
  )}
536
534
  {filteredChildren}
537
535
  </ul>
@@ -553,9 +551,12 @@ SelectContent.displayName = "SelectContent";
553
551
  * @returns The rendered select item
554
552
  */
555
553
  export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
556
- ({ value, children, disabled = false, className, onClick }, ref) => {
557
- const { value: selectedValue, actions, registerItem, unregisterItem } = useSelectContext();
554
+ ({ value, children, disabled = false, className, onClick, showCheckmark: propShowCheckmark }, ref) => {
555
+ const { value: selectedValue, actions, registerItem, unregisterItem, showCheckmark: contextShowCheckmark = true } = useSelectContext();
558
556
  const isSelected = selectedValue === value;
557
+
558
+ // Use prop if provided, otherwise use context value, default to true
559
+ const showCheckmark = propShowCheckmark ?? contextShowCheckmark;
559
560
 
560
561
  const itemText = getTextContent(children);
561
562
 
@@ -571,9 +572,11 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
571
572
  }
572
573
  };
573
574
  }, [value, itemText, registerItem, unregisterItem]);
574
-
575
+
575
576
  const handleMouseDown = (e: React.MouseEvent) => {
576
577
  if (!disabled) {
578
+ // CRITICAL FIX: Prevent event from bubbling to avoid interference with table row interactions
579
+ e.stopPropagation();
577
580
  const event = new CustomEvent('selectItemMouseDown', { detail: { value } });
578
581
  document.dispatchEvent(event);
579
582
  }
@@ -581,6 +584,8 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
581
584
 
582
585
  const handleClick = (e: React.MouseEvent) => {
583
586
  if (!disabled) {
587
+ // CRITICAL FIX: Prevent event from bubbling to avoid interference with table row clicks
588
+ e.stopPropagation();
584
589
  if (onClick) {
585
590
  onClick(e);
586
591
  }
@@ -634,7 +639,7 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
634
639
  tabIndex={disabled ? -1 : 0}
635
640
  >
636
641
  {children}
637
- {isSelected && (
642
+ {isSelected && showCheckmark && (
638
643
  <Check className="absolute right-2 size-4 flex-shrink-0 mt-0.5" />
639
644
  )}
640
645
  </li>
@@ -649,18 +654,24 @@ SelectItem.displayName = "SelectItem";
649
654
 
650
655
  /**
651
656
  * Select group component.
652
- * Groups related select items together.
657
+ * Groups related select items together using a nested list structure.
653
658
  *
654
659
  * @param props - Select group configuration
655
- * @param ref - Forwarded ref to the div element
660
+ * @param ref - Forwarded ref to the ul element
656
661
  * @returns The rendered select group
657
662
  */
658
- export const SelectGroup = React.forwardRef<HTMLDivElement, { children: React.ReactNode; className?: string }>(
663
+ export const SelectGroup = React.forwardRef<HTMLUListElement, { children: React.ReactNode; className?: string }>(
659
664
  ({ children, className }, ref) => {
660
665
  return (
661
- <div ref={ref} className={cn("p-1", className)} data-testid="select-group">
662
- {children}
663
- </div>
666
+ <li className="list-none" data-testid="select-group-wrapper">
667
+ <ul
668
+ ref={ref}
669
+ className={cn("p-1 list-none m-0", className)}
670
+ data-testid="select-group"
671
+ >
672
+ {children}
673
+ </ul>
674
+ </li>
664
675
  );
665
676
  }
666
677
  );
@@ -671,15 +682,15 @@ SelectGroup.displayName = "SelectGroup";
671
682
  * Provides a label for a group of select items.
672
683
  *
673
684
  * @param props - Select label configuration
674
- * @param ref - Forwarded ref to the div element
685
+ * @param ref - Forwarded ref to the li element
675
686
  * @returns The rendered select label
676
687
  */
677
- export const SelectLabel = React.forwardRef<HTMLDivElement, { children: React.ReactNode; className?: string }>(
688
+ export const SelectLabel = React.forwardRef<HTMLLIElement, { children: React.ReactNode; className?: string }>(
678
689
  ({ children, className }, ref) => {
679
690
  return (
680
- <div ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", className)} data-testid="select-label">
691
+ <li ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", className)} data-testid="select-label">
681
692
  {children}
682
- </div>
693
+ </li>
683
694
  );
684
695
  }
685
696
  );
@@ -690,13 +701,13 @@ SelectLabel.displayName = "SelectLabel";
690
701
  * Provides visual separation between groups of select items.
691
702
  *
692
703
  * @param props - Select separator configuration
693
- * @param ref - Forwarded ref to the div element
704
+ * @param ref - Forwarded ref to the hr element
694
705
  * @returns The rendered select separator
695
706
  */
696
- export const SelectSeparator = React.forwardRef<HTMLDivElement, { className?: string }>(
707
+ export const SelectSeparator = React.forwardRef<HTMLHRElement, { className?: string }>(
697
708
  ({ className }, ref) => {
698
709
  return (
699
- <div
710
+ <hr
700
711
  ref={ref}
701
712
  className={cn("my-1 h-px bg-sec-200", className)}
702
713
  data-testid="select-separator"
@@ -67,6 +67,7 @@ export interface SelectContextValue extends SelectState {
67
67
  registerItem?: (value: string, text: string) => void;
68
68
  unregisterItem?: (value: string) => void;
69
69
  direction?: SelectDirection;
70
+ showCheckmark?: boolean;
70
71
  }
71
72
 
72
73
  /**
@@ -74,12 +75,13 @@ export interface SelectContextValue extends SelectState {
74
75
  */
75
76
  export interface SelectProps
76
77
  extends Omit<
77
- React.HTMLAttributes<HTMLFormElement>,
78
+ React.HTMLAttributes<HTMLFieldSetElement>,
78
79
  "onChange" | "onKeyDown" | "onFocus" | "onBlur"
79
80
  > {
80
81
  children: React.ReactNode;
81
82
  className?: string;
82
83
  direction?: SelectDirection;
84
+ showCheckmark?: boolean;
83
85
  }
84
86
 
85
87
  /**
@@ -120,4 +122,5 @@ export interface SelectItemProps {
120
122
  disabled?: boolean;
121
123
  className?: string;
122
124
  onClick?: (e: React.MouseEvent) => void;
125
+ showCheckmark?: boolean;
123
126
  }
@@ -142,6 +142,8 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
142
142
  className,
143
143
  showAvatar = true,
144
144
  }) {
145
+ // Call all hooks unconditionally at the top level
146
+ // Hooks must be called in the same order on every render
145
147
  const userInfo = useMemo(() => {
146
148
  if (!user) return null;
147
149
  return {
@@ -156,11 +158,7 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
156
158
  if (onSignOut) await onSignOut();
157
159
  }, [onSignOut]);
158
160
 
159
- if (!user || !userInfo) {
160
- return null; // Or a loading/login button
161
- }
162
-
163
- // Password change dialog state and handlers (moved closer to Dialog usage)
161
+ // Password change dialog state and handlers - must be called before any early returns
164
162
  const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);
165
163
 
166
164
  const handlePasswordChange = useCallback(async (newPassword: string, confirmPassword: string) => {
@@ -170,6 +168,11 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
170
168
  return await onChangePassword(newPassword, confirmPassword);
171
169
  }, [onChangePassword]);
172
170
 
171
+ // Early return after all hooks have been called
172
+ if (!user || !userInfo) {
173
+ return null; // Or a loading/login button
174
+ }
175
+
173
176
  return (
174
177
  <>
175
178
  <Select className={className}>
@@ -210,7 +213,7 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
210
213
  </Select>
211
214
 
212
215
  <Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>
213
- <DialogContent>
216
+ <DialogContent persistOpenState={false}>
214
217
  <DialogHeader>
215
218
  <DialogTitle>Change Password</DialogTitle>
216
219
  </DialogHeader>
@@ -137,7 +137,7 @@ describe('Service Hooks', () => {
137
137
  it('should return AuthService from context', () => {
138
138
  const mockService = createMockService('auth');
139
139
  const wrapper = ({ children }: { children: React.ReactNode }) => (
140
- <div>{children}</div>
140
+ <section>{children}</section>
141
141
  );
142
142
 
143
143
  // Mock the context with proper structure
@@ -150,7 +150,7 @@ describe('Service Hooks', () => {
150
150
 
151
151
  it('should throw error when used outside provider', () => {
152
152
  const wrapper = ({ children }: { children: React.ReactNode }) => (
153
- <div>{children}</div>
153
+ <section>{children}</section>
154
154
  );
155
155
 
156
156
  // Mock the context to return null
@@ -164,7 +164,7 @@ describe('Service Hooks', () => {
164
164
  it('should subscribe to service changes', () => {
165
165
  const mockService = createMockService('auth');
166
166
  const wrapper = ({ children }: { children: React.ReactNode }) => (
167
- <div>{children}</div>
167
+ <section>{children}</section>
168
168
  );
169
169
 
170
170
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -179,7 +179,7 @@ describe('Service Hooks', () => {
179
179
  it('should return OrganisationService from context', () => {
180
180
  const mockService = createMockService('organisation');
181
181
  const wrapper = ({ children }: { children: React.ReactNode }) => (
182
- <div>{children}</div>
182
+ <section>{children}</section>
183
183
  );
184
184
 
185
185
  mockUseContext.mockReturnValue({ organisationService: mockService });
@@ -191,7 +191,7 @@ describe('Service Hooks', () => {
191
191
 
192
192
  it('should throw error when used outside provider', () => {
193
193
  const wrapper = ({ children }: { children: React.ReactNode }) => (
194
- <div>{children}</div>
194
+ <section>{children}</section>
195
195
  );
196
196
 
197
197
  mockUseContext.mockReturnValue(null);
@@ -206,7 +206,7 @@ describe('Service Hooks', () => {
206
206
  it('should return EventService from context', () => {
207
207
  const mockService = createMockService('event');
208
208
  const wrapper = ({ children }: { children: React.ReactNode }) => (
209
- <div>{children}</div>
209
+ <section>{children}</section>
210
210
  );
211
211
 
212
212
  mockUseContext.mockReturnValue({ eventService: mockService });
@@ -218,7 +218,7 @@ describe('Service Hooks', () => {
218
218
 
219
219
  it('should throw error when used outside provider', () => {
220
220
  const wrapper = ({ children }: { children: React.ReactNode }) => (
221
- <div>{children}</div>
221
+ <section>{children}</section>
222
222
  );
223
223
 
224
224
  mockUseContext.mockReturnValue(null);
@@ -233,7 +233,7 @@ describe('Service Hooks', () => {
233
233
  it('should return InactivityService from context', () => {
234
234
  const mockService = createMockService('inactivity');
235
235
  const wrapper = ({ children }: { children: React.ReactNode }) => (
236
- <div>{children}</div>
236
+ <section>{children}</section>
237
237
  );
238
238
 
239
239
  vi.spyOn(React, 'useContext').mockReturnValue({ inactivityService: mockService });
@@ -245,7 +245,7 @@ describe('Service Hooks', () => {
245
245
 
246
246
  it('should throw error when used outside provider', () => {
247
247
  const wrapper = ({ children }: { children: React.ReactNode }) => (
248
- <div>{children}</div>
248
+ <section>{children}</section>
249
249
  );
250
250
 
251
251
  mockUseContext.mockReturnValue(null);
@@ -276,7 +276,7 @@ describe('Service Hooks', () => {
276
276
  };
277
277
 
278
278
  const wrapper = ({ children }: { children: React.ReactNode }) => (
279
- <div>{children}</div>
279
+ <section>{children}</section>
280
280
  );
281
281
 
282
282
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -327,7 +327,7 @@ describe('Service Hooks', () => {
327
327
  };
328
328
 
329
329
  const wrapper = ({ children }: { children: React.ReactNode }) => (
330
- <div>{children}</div>
330
+ <section>{children}</section>
331
331
  );
332
332
 
333
333
  mockUseContext.mockReturnValue({ rbacService: mockService });
@@ -382,7 +382,7 @@ describe('Service Hooks', () => {
382
382
  };
383
383
 
384
384
  const wrapper = ({ children }: { children: React.ReactNode }) => (
385
- <div>{children}</div>
385
+ <section>{children}</section>
386
386
  );
387
387
 
388
388
  mockUseContext.mockReturnValue({ organisationService: mockService });
@@ -434,7 +434,7 @@ describe('Service Hooks', () => {
434
434
  };
435
435
 
436
436
  const wrapper = ({ children }: { children: React.ReactNode }) => (
437
- <div>{children}</div>
437
+ <section>{children}</section>
438
438
  );
439
439
 
440
440
  mockUseContext.mockReturnValue({ eventService: mockService });
@@ -527,7 +527,7 @@ describe('Service Hooks', () => {
527
527
  };
528
528
 
529
529
  const wrapper = ({ children }: { children: React.ReactNode }) => (
530
- <div>{children}</div>
530
+ <section>{children}</section>
531
531
  );
532
532
 
533
533
  // Test individual hooks
@@ -570,7 +570,7 @@ describe('Service Hooks', () => {
570
570
  };
571
571
 
572
572
  const wrapper = ({ children }: { children: React.ReactNode }) => (
573
- <div>{children}</div>
573
+ <section>{children}</section>
574
574
  );
575
575
 
576
576
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -600,7 +600,7 @@ describe('Service Hooks', () => {
600
600
  };
601
601
 
602
602
  const wrapper = ({ children }: { children: React.ReactNode }) => (
603
- <div>{children}</div>
603
+ <section>{children}</section>
604
604
  );
605
605
 
606
606
  mockUseContext.mockReturnValue({ authService: mockService });