@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -241,15 +241,19 @@ describe('[component] PublicPageLayout', () => {
241
241
  });
242
242
 
243
243
  it('renders loading state with proper layout classes', () => {
244
- const { container } = render(
244
+ render(
245
245
  <PublicPageLayout eventCode="EVENT123" isLoading={true}>
246
246
  <div>Test Content</div>
247
247
  </PublicPageLayout>
248
248
  );
249
249
 
250
- const loadingContainer = container.querySelector('.min-h-screen');
250
+ // The loading state renders a <p> tag with grid and place-items-center classes
251
+ // There may be multiple "Loading..." texts (from LoadingSpinner mock and actual text)
252
+ // So we query by the container element using getAllByText and find the one in the <p> tag
253
+ const loadingTexts = screen.getAllByText('Loading...');
254
+ const loadingContainer = loadingTexts.find(text => text.closest('p'))?.closest('p');
251
255
  expect(loadingContainer).toBeInTheDocument();
252
- expect(loadingContainer).toHaveClass('bg-background', 'flex', 'items-center', 'justify-center');
256
+ expect(loadingContainer).toHaveClass('grid', 'place-items-center', 'text-center', 'size-full');
253
257
  });
254
258
  });
255
259
 
@@ -312,14 +312,11 @@ export function PublicPageLayout({
312
312
  return <LoadingFallback />;
313
313
  }
314
314
  return (
315
- <div className="min-h-screen bg-background flex items-center justify-center">
316
- <div className="max-w-md mx-auto text-center px-4">
317
- <LoadingSpinner size="lg" className="mx-auto mb-4" />
318
- {loadingMessage && (
319
- <p className="text-sec-600">{loadingMessage}</p>
320
- )}
321
- </div>
322
- </div>
315
+ <p className="grid place-items-center text-center size-full">
316
+ <LoadingSpinner
317
+ size="lg"/><br />
318
+ {loadingMessage || 'Loading...'}
319
+ </p>
323
320
  );
324
321
  }
325
322
 
@@ -40,20 +40,20 @@ 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>(
46
+ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSelectStateProps>(
47
47
  ({
48
48
  children,
49
49
  className,
50
50
  direction = 'down',
51
51
  ...selectProps
52
52
  }, ref) => {
53
- const internalRef = React.useRef<HTMLFormElement>(null);
53
+ const internalRef = React.useRef<HTMLFieldSetElement>(null);
54
54
  const selectRef = React.useMemo(() => {
55
55
  if (ref && typeof ref === 'object' && 'current' in ref) {
56
- return ref as React.RefObject<HTMLFormElement | null>;
56
+ return ref as React.RefObject<HTMLFieldSetElement | null>;
57
57
  }
58
58
  return internalRef;
59
59
  }, [ref]);
@@ -201,20 +201,16 @@ export const Select = React.forwardRef<HTMLFormElement, SelectProps & UseSelectS
201
201
  }), [state, actions, registerItem, unregisterItem, direction]);
202
202
 
203
203
  return (
204
- <form
204
+ <fieldset
205
205
  ref={selectRef}
206
- className={cn("relative", className)}
206
+ className={cn("relative border-0 p-0 m-0", className)}
207
207
  data-value={state.value}
208
208
  data-testid="select-root"
209
- onSubmit={(e) => {
210
- e.preventDefault();
211
- e.stopPropagation();
212
- }}
213
209
  >
214
210
  <SelectContext.Provider value={contextValue}>
215
211
  {children}
216
212
  </SelectContext.Provider>
217
- </form>
213
+ </fieldset>
218
214
  );
219
215
  }
220
216
  );
@@ -304,6 +300,18 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
304
300
  ...props
305
301
  };
306
302
 
303
+ // Call all hooks unconditionally at the top level
304
+ // Hooks must be called in the same order on every render
305
+ // Simple ref forwarding - must be called before any early returns
306
+ const handleRef = React.useCallback((node: HTMLButtonElement | null) => {
307
+ if (typeof ref === 'function') {
308
+ ref(node);
309
+ } else if (ref) {
310
+ (ref as React.MutableRefObject<HTMLButtonElement | null>).current = node;
311
+ }
312
+ }, [ref]);
313
+
314
+ // Early return after all hooks have been called
307
315
  if (asChild) {
308
316
  const childElement = children as React.ReactElement<{ children?: React.ReactNode; [key: string]: unknown }>;
309
317
  const childChildren = React.Children.toArray(childElement.props.children);
@@ -340,16 +348,6 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
340
348
  });
341
349
  }
342
350
 
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
351
  return (
354
352
  <Button
355
353
  ref={handleRef}
@@ -574,6 +572,8 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
574
572
 
575
573
  const handleMouseDown = (e: React.MouseEvent) => {
576
574
  if (!disabled) {
575
+ // CRITICAL FIX: Prevent event from bubbling to avoid interference with table row interactions
576
+ e.stopPropagation();
577
577
  const event = new CustomEvent('selectItemMouseDown', { detail: { value } });
578
578
  document.dispatchEvent(event);
579
579
  }
@@ -581,6 +581,8 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
581
581
 
582
582
  const handleClick = (e: React.MouseEvent) => {
583
583
  if (!disabled) {
584
+ // CRITICAL FIX: Prevent event from bubbling to avoid interference with table row clicks
585
+ e.stopPropagation();
584
586
  if (onClick) {
585
587
  onClick(e);
586
588
  }
@@ -74,7 +74,7 @@ export interface SelectContextValue extends SelectState {
74
74
  */
75
75
  export interface SelectProps
76
76
  extends Omit<
77
- React.HTMLAttributes<HTMLFormElement>,
77
+ React.HTMLAttributes<HTMLFieldSetElement>,
78
78
  "onChange" | "onKeyDown" | "onFocus" | "onBlur"
79
79
  > {
80
80
  children: React.ReactNode;
@@ -21,7 +21,7 @@ vi.mock('lucide-react', () => ({
21
21
 
22
22
  // Mock the PasswordChangeForm component
23
23
  vi.mock('../PasswordChange/PasswordChangeForm', () => ({
24
- PasswordChangeForm: ({ onSubmit }: { onSubmit: (values: { newPassword: string; confirmPassword: string }) => Promise<{ error?: { message?: string; code?: string } }> }) => {
24
+ PasswordChangeForm: ({ onSubmit, onSuccess }: { onSubmit: (values: { newPassword: string; confirmPassword: string }) => Promise<{ error?: { message?: string; code?: string } }>; onSuccess?: () => void }) => {
25
25
  const [isSubmitting, setIsSubmitting] = React.useState(false);
26
26
  const [error, setError] = React.useState<string | null>(null);
27
27
 
@@ -33,6 +33,9 @@ vi.mock('../PasswordChange/PasswordChangeForm', () => ({
33
33
  const result = await onSubmit({ newPassword: 'newpass123', confirmPassword: 'newpass123' });
34
34
  if (result.error) {
35
35
  setError(result.error.message);
36
+ } else {
37
+ // Call onSuccess on successful password change
38
+ onSuccess?.();
36
39
  }
37
40
  } catch (err) {
38
41
  const errorObj = err instanceof Error ? err : new Error('An unexpected error occurred');
@@ -92,9 +95,7 @@ vi.mock('../Select', () => ({
92
95
  // Mock the Dialog components
93
96
  vi.mock('../Dialog', () => ({
94
97
  Dialog: ({ children, open, onOpenChange }: { children: React.ReactNode; open: boolean; onOpenChange: (open: boolean) => void }) => (
95
- <div data-testid="dialog" data-open={open}>
96
- {children}
97
- </div>
98
+ open ? <div data-testid="dialog" role="dialog" data-open={open}>{children}</div> : null
98
99
  ),
99
100
  DialogContent: ({ children, className }: { children: React.ReactNode; className?: string }) => (
100
101
  <div data-testid="dialog-content" className={className}>
@@ -109,12 +110,17 @@ vi.mock('../Dialog', () => ({
109
110
  DialogTitle: ({ children }: { children: React.ReactNode }) => (
110
111
  <h2 data-testid="dialog-title">{children}</h2>
111
112
  ),
113
+ DialogDescription: ({ children }: { children: React.ReactNode }) => (
114
+ <p data-testid="dialog-description">{children}</p>
115
+ ),
112
116
  DialogTrigger: ({ children, asChild }: { children: React.ReactNode; asChild?: boolean }) => (
113
117
  <div data-testid="dialog-trigger">
114
118
  {asChild ? children : <button>{children}</button>}
115
119
  </div>
116
120
  ),
117
- DialogOverlay: () => <div data-testid="dialog-overlay" />,
121
+ DialogClose: ({ children, onClick }: { children?: React.ReactNode; onClick?: () => void }) => (
122
+ <button data-testid="dialog-close" onClick={onClick}>{children || 'Close'}</button>
123
+ ),
118
124
  }));
119
125
 
120
126
  // Mock the Avatar component
@@ -412,6 +418,32 @@ describe('UserMenu Component', () => {
412
418
  });
413
419
  });
414
420
 
421
+ it('closes dialog when password change succeeds', async () => {
422
+ const user = createMockUser();
423
+ const handleChangePassword = vi.fn().mockResolvedValue({});
424
+ const userEventInstance = userEvent.setup();
425
+
426
+ renderWithProviders(<UserMenu user={user} onChangePassword={handleChangePassword} />);
427
+
428
+ const trigger = screen.getByRole('button', { name: 'Test User' });
429
+ await userEventInstance.click(trigger);
430
+
431
+ const changePasswordButton = screen.getByTestId('select-item-change-password');
432
+ await userEventInstance.click(changePasswordButton);
433
+
434
+ // Verify dialog is open
435
+ expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
436
+
437
+ const submitButton = screen.getByRole('button', { name: 'Change Password' });
438
+ await userEventInstance.click(submitButton);
439
+
440
+ // Wait for dialog to close
441
+ await waitFor(() => {
442
+ const dialog = screen.queryByTestId('dialog-content');
443
+ expect(dialog).not.toBeInTheDocument();
444
+ }, { timeout: 3000 });
445
+ });
446
+
415
447
  it('keeps dialog open when password change fails', async () => {
416
448
  const user = createMockUser();
417
449
  const handleChangePassword = vi.fn().mockResolvedValue({ error: { message: 'Password too weak' } });
@@ -434,7 +466,7 @@ describe('UserMenu Component', () => {
434
466
  expect(screen.getByTestId('error-message')).toHaveTextContent('Password too weak');
435
467
  });
436
468
 
437
- // Dialog should still be open
469
+ // Dialog should still be open (onSuccess should not be called when there's an error)
438
470
  expect(screen.getByTestId('dialog-content')).toBeInTheDocument();
439
471
  });
440
472
 
@@ -117,9 +117,7 @@ import {
117
117
  Dialog,
118
118
  DialogContent,
119
119
  DialogHeader,
120
- DialogTitle,
121
- DialogTrigger,
122
- DialogOverlay
120
+ DialogTitle
123
121
  } from '../Dialog';
124
122
  import { PasswordChangeForm, PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';
125
123
  import { Avatar } from '../Avatar';
@@ -144,8 +142,8 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
144
142
  className,
145
143
  showAvatar = true,
146
144
  }) {
147
- const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);
148
-
145
+ // Call all hooks unconditionally at the top level
146
+ // Hooks must be called in the same order on every render
149
147
  const userInfo = useMemo(() => {
150
148
  if (!user) return null;
151
149
  return {
@@ -160,12 +158,23 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
160
158
  if (onSignOut) await onSignOut();
161
159
  }, [onSignOut]);
162
160
 
161
+ // Password change dialog state and handlers - must be called before any early returns
162
+ const [isPasswordDialogOpen, setPasswordDialogOpen] = useState(false);
163
+
164
+ const handlePasswordChange = useCallback(async (newPassword: string, confirmPassword: string) => {
165
+ if (!onChangePassword) {
166
+ return { error: { message: 'Password change not configured' } };
167
+ }
168
+ return await onChangePassword(newPassword, confirmPassword);
169
+ }, [onChangePassword]);
170
+
171
+ // Early return after all hooks have been called
163
172
  if (!user || !userInfo) {
164
173
  return null; // Or a loading/login button
165
174
  }
166
175
 
167
176
  return (
168
- <Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>
177
+ <>
169
178
  <Select className={className}>
170
179
  <SelectTrigger asChild>
171
180
  <Button variant="outline" className="flex items-center gap-2" aria-label={userInfo.displayName}>
@@ -185,42 +194,38 @@ export const UserMenu = React.memo<UserMenuProps>(function UserMenu({
185
194
  <SelectLabel className="font-normal">
186
195
  <li className="pt-2">
187
196
  {userInfo.displayName}<br/>
188
- <span className="text-muted-foreground">{userInfo.email}</span>
197
+ <small>{userInfo.email}</small>
189
198
  </li>
190
199
  </SelectLabel>
191
200
  <SelectSeparator />
192
- <DialogTrigger asChild>
193
- <SelectItem value="change-password">
194
- <KeyRound className="mr-2 size-4" />
195
- <span>Change Password</span>
196
- </SelectItem>
197
- </DialogTrigger>
201
+ <SelectItem
202
+ value="change-password"
203
+ onClick={() => setPasswordDialogOpen(true)}
204
+ >
205
+ <KeyRound className="inline-block mr-2 size-4" />
206
+ Change Password
207
+ </SelectItem>
198
208
  <SelectItem value="sign-out" onClick={handleSignOut}>
199
- <LogOut className="mr-2 size-4" />
200
- <span>Sign out</span>
209
+ <LogOut className="inline-block mr-2 size-4" />
210
+ Sign out
201
211
  </SelectItem>
202
212
  </SelectContent>
203
213
  </Select>
204
214
 
205
- <DialogOverlay />
206
- <DialogContent className={className}>
207
- <DialogHeader>
208
- <DialogTitle>Change Password</DialogTitle>
209
- </DialogHeader>
210
- <PasswordChangeForm
211
- onSubmit={async ({ newPassword, confirmPassword }) => {
212
- if (onChangePassword) {
213
- const { error } = await onChangePassword(newPassword, confirmPassword);
214
- if (!error) {
215
- setPasswordDialogOpen(false);
216
- }
217
- return { error };
218
- }
219
- return {};
220
- }}
221
- />
222
- </DialogContent>
223
- </Dialog>
215
+ <Dialog open={isPasswordDialogOpen} onOpenChange={setPasswordDialogOpen}>
216
+ <DialogContent persistOpenState={false}>
217
+ <DialogHeader>
218
+ <DialogTitle>Change Password</DialogTitle>
219
+ </DialogHeader>
220
+ <PasswordChangeForm
221
+ onSubmit={async ({ newPassword, confirmPassword }) => {
222
+ return await handlePasswordChange(newPassword, confirmPassword);
223
+ }}
224
+ onSuccess={() => setPasswordDialogOpen(false)}
225
+ />
226
+ </DialogContent>
227
+ </Dialog>
228
+ </>
224
229
  );
225
230
  });
226
231
 
@@ -84,7 +84,6 @@ export {
84
84
  export {
85
85
  Dialog,
86
86
  DialogPortal,
87
- DialogOverlay,
88
87
  DialogTrigger,
89
88
  DialogClose,
90
89
  DialogContent,
@@ -98,11 +97,11 @@ export type {
98
97
  DialogProps,
99
98
  DialogTriggerProps,
100
99
  DialogContentProps,
101
- DialogOverlayProps,
100
+ DialogPortalProps,
101
+ DialogCloseProps,
102
102
  DialogHeaderProps,
103
103
  DialogFooterProps,
104
- DialogTitleProps,
105
- DialogDescriptionProps,
104
+ DialogBodyProps,
106
105
  DialogSize
107
106
  } from './Dialog/Dialog';
108
107
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Main entry point for pace-core ESLint rules
3
+ * @package @jmruthers/pace-core
4
+ * @module ESLintRules
5
+ *
6
+ * This module exports all pace-core compliance ESLint rules organized by category.
7
+ */
8
+
9
+ const complianceRules = require('./rules/compliance.cjs');
10
+ const componentRules = require('./rules/components.cjs');
11
+ const rbacRules = require('./rules/rbac.cjs');
12
+ const importRules = require('./rules/imports.cjs');
13
+
14
+ module.exports = {
15
+ rules: {
16
+ ...complianceRules.rules,
17
+ ...componentRules.rules,
18
+ ...rbacRules.rules,
19
+ ...importRules.rules,
20
+ }
21
+ };
22
+