@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
@@ -1,1328 +0,0 @@
1
- ---
2
- lastUpdated: 2025-11-18T17:00:00+11:00
3
- version: 0.5.181
4
- reviewedBy: documentation-standards-audit
5
- ---
6
-
7
- # Performance Best Practices
8
-
9
- > **📚 Complete Performance Guide** | [← Back to Documentation](./README.md) | [Installation Guide](../getting-started/installation-guide.md)
10
-
11
- Performance is crucial for user experience. This comprehensive guide provides all performance optimization techniques for `@jmruthers/pace-core` applications, from basic strategies to advanced optimization.
12
-
13
- ## Overview
14
-
15
- Performance optimization in `@jmruthers/pace-core` covers:
16
-
17
- - **Component Rendering**: Minimizing unnecessary re-renders
18
- - **Data Fetching**: Efficient data loading and caching
19
- - **Bundle Size**: Optimizing package size and tree shaking
20
- - **Memory Management**: Preventing memory leaks
21
- - **Network Optimization**: Reducing API calls and payload size
22
- - **Advanced Techniques**: Code splitting, lazy loading, and optimization tools
23
-
24
- ## Component Performance
25
-
26
- ### 1. Memoization Strategies
27
-
28
- ```typescript
29
- import { useMemo, useCallback } from 'react';
30
- import { useEvents } from '@jmruthers/pace-core';
31
-
32
- function OptimizedEventList() {
33
- const { events, loading } = useEvents();
34
-
35
- // Memoize expensive calculations
36
- const sortedEvents = useMemo(() => {
37
- return events?.sort((a, b) =>
38
- new Date(a.start_date).getTime() - new Date(b.start_date).getTime()
39
- ) || [];
40
- }, [events]);
41
-
42
- // Memoize filtered data
43
- const upcomingEvents = useMemo(() => {
44
- const now = new Date();
45
- return sortedEvents.filter(event =>
46
- new Date(event.start_date) > now
47
- );
48
- }, [sortedEvents]);
49
-
50
- // Memoize event groups
51
- const eventsByDate = useMemo(() => {
52
- return upcomingEvents.reduce((groups, event) => {
53
- const date = event.start_date.split('T')[0];
54
- if (!groups[date]) groups[date] = [];
55
- groups[date].push(event);
56
- return groups;
57
- }, {});
58
- }, [upcomingEvents]);
59
-
60
- if (loading) return <div>Loading...</div>;
61
-
62
- return (
63
- <div>
64
- {Object.entries(eventsByDate).map(([date, events]) => (
65
- <div key={date}>
66
- <h3>{date}</h3>
67
- {events.map(event => (
68
- <EventCard key={event.id} event={event} />
69
- ))}
70
- </div>
71
- ))}
72
- </div>
73
- );
74
- }
75
- ```
76
-
77
- ### 2. Callback Optimization
78
-
79
- ```typescript
80
- import { useCallback } from 'react';
81
- import { useEvents } from '@jmruthers/pace-core';
82
-
83
- function EventManager() {
84
- const { events, setSelectedEvent, refreshEvents } = useEvents();
85
-
86
- // Memoize event handlers
87
- const handleEventSelect = useCallback((event) => {
88
- setSelectedEvent(event);
89
- }, [setSelectedEvent]);
90
-
91
- const handleRefresh = useCallback(() => {
92
- refreshEvents();
93
- }, [refreshEvents]);
94
-
95
- const handleEventDelete = useCallback(async (eventId) => {
96
- try {
97
- await deleteEvent(eventId);
98
- refreshEvents();
99
- } catch (error) {
100
- console.error('Failed to delete event:', error);
101
- }
102
- }, [refreshEvents]);
103
-
104
- return (
105
- <div>
106
- <button onClick={handleRefresh}>Refresh</button>
107
- {events.map(event => (
108
- <EventCard
109
- key={event.id}
110
- event={event}
111
- onSelect={handleEventSelect}
112
- onDelete={handleEventDelete}
113
- />
114
- ))}
115
- </div>
116
- );
117
- }
118
- ```
119
-
120
- ### 3. Component Splitting
121
-
122
- ```typescript
123
- // Split large components into smaller, focused components
124
- function EventDashboard() {
125
- const { events, loading } = useEvents();
126
-
127
- if (loading) return <LoadingSpinner />;
128
-
129
- return (
130
- <div className="dashboard">
131
- <EventSummary events={events} />
132
- <EventCalendar events={events} />
133
- <EventList events={events} />
134
- </div>
135
- );
136
- }
137
-
138
- // Separate components for better performance
139
- const EventSummary = React.memo(({ events }) => {
140
- const stats = useMemo(() => ({
141
- total: events.length,
142
- upcoming: events.filter(e => new Date(e.start_date) > new Date()).length,
143
- past: events.filter(e => new Date(e.start_date) < new Date()).length,
144
- }), [events]);
145
-
146
- return (
147
- <div className="summary">
148
- <div>Total: {stats.total}</div>
149
- <div>Upcoming: {stats.upcoming}</div>
150
- <div>Past: {stats.past}</div>
151
- </div>
152
- );
153
- });
154
-
155
- const EventCalendar = React.memo(({ events }) => {
156
- // Calendar implementation
157
- return <div className="calendar">...</div>;
158
- });
159
-
160
- const EventList = React.memo(({ events }) => {
161
- // List implementation
162
- return <div className="list">...</div>;
163
- });
164
- ```
165
-
166
- ## Data Fetching Optimization
167
-
168
- ### 1. Efficient Data Loading
169
-
170
- ```typescript
171
- import { useEvents } from '@jmruthers/pace-core';
172
-
173
- function OptimizedEventLoader() {
174
- const { events, loading, error, refreshEvents } = useEvents();
175
-
176
- // Implement pagination for large datasets
177
- const [page, setPage] = useState(1);
178
- const [pageSize, setPageSize] = useState(20);
179
-
180
- const paginatedEvents = useMemo(() => {
181
- const start = (page - 1) * pageSize;
182
- const end = start + pageSize;
183
- return events.slice(start, end);
184
- }, [events, page, pageSize]);
185
-
186
- // Implement virtual scrolling for very large lists
187
- const VirtualizedEventList = useMemo(() => {
188
- return React.memo(({ events }) => {
189
- return (
190
- <div className="virtual-list">
191
- {events.map((event, index) => (
192
- <EventRow key={event.id} event={event} index={index} />
193
- ))}
194
- </div>
195
- );
196
- });
197
- }, []);
198
-
199
- return (
200
- <div>
201
- <VirtualizedEventList events={paginatedEvents} />
202
- <Pagination
203
- currentPage={page}
204
- totalPages={Math.ceil(events.length / pageSize)}
205
- onPageChange={setPage}
206
- />
207
- </div>
208
- );
209
- }
210
- ```
211
-
212
- ### 2. Caching Strategies
213
-
214
- ```typescript
215
- import { useMemoizedCallback } from '@jmruthers/pace-core';
216
-
217
- function CachedDataComponent() {
218
- const { events, refreshEvents } = useEvents();
219
-
220
- // Cache expensive operations
221
- const eventStats = useMemo(() => {
222
- return events.reduce((stats, event) => {
223
- const month = new Date(event.start_date).getMonth();
224
- stats[month] = (stats[month] || 0) + 1;
225
- return stats;
226
- }, {});
227
- }, [events]);
228
-
229
- // Cache filtered results
230
- const [filter, setFilter] = useState('');
231
- const filteredEvents = useMemo(() => {
232
- if (!filter) return events;
233
- return events.filter(event =>
234
- event.name.toLowerCase().includes(filter.toLowerCase())
235
- );
236
- }, [events, filter]);
237
-
238
- // Debounced search
239
- const debouncedSetFilter = useMemoizedCallback(
240
- (value) => setFilter(value),
241
- [],
242
- 300
243
- );
244
-
245
- return (
246
- <div>
247
- <input
248
- type="text"
249
- placeholder="Search events..."
250
- onChange={(e) => debouncedSetFilter(e.target.value)}
251
- />
252
- <EventList events={filteredEvents} />
253
- <EventStats stats={eventStats} />
254
- </div>
255
- );
256
- }
257
- ```
258
-
259
- ### 3. Background Data Updates
260
-
261
- ```typescript
262
- import { useEffect, useRef } from 'react';
263
- import { useEvents } from '@jmruthers/pace-core';
264
-
265
- function AutoRefreshingEventList() {
266
- const { events, refreshEvents } = useEvents();
267
- const intervalRef = useRef(null);
268
-
269
- // Auto-refresh data in background
270
- useEffect(() => {
271
- intervalRef.current = setInterval(() => {
272
- refreshEvents();
273
- }, 30000); // Refresh every 30 seconds
274
-
275
- return () => {
276
- if (intervalRef.current) {
277
- clearInterval(intervalRef.current);
278
- }
279
- };
280
- }, [refreshEvents]);
281
-
282
- // Pause refresh when tab is not visible
283
- useEffect(() => {
284
- const handleVisibilityChange = () => {
285
- if (document.hidden) {
286
- if (intervalRef.current) {
287
- clearInterval(intervalRef.current);
288
- }
289
- } else {
290
- intervalRef.current = setInterval(() => {
291
- refreshEvents();
292
- }, 30000);
293
- }
294
- };
295
-
296
- document.addEventListener('visibilitychange', handleVisibilityChange);
297
- return () => {
298
- document.removeEventListener('visibilitychange', handleVisibilityChange);
299
- };
300
- }, [refreshEvents]);
301
-
302
- return <EventList events={events} />;
303
- }
304
- ```
305
-
306
- ## Bundle Size Optimization
307
-
308
- ### 1. Tree Shaking
309
-
310
- ```typescript
311
- // Import only what you need
312
- import { Button, DataTable } from '@jmruthers/pace-core';
313
- // Instead of: import * from '@jmruthers/pace-core';
314
-
315
- // Use dynamic imports for large components
316
- const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
317
-
318
- function App() {
319
- return (
320
- <Suspense fallback={<div>Loading...</div>}>
321
- <HeavyComponent />
322
- </Suspense>
323
- );
324
- }
325
- ```
326
-
327
- ### 2. Code Splitting
328
-
329
- ```typescript
330
- // Split routes by feature
331
- const AdminDashboard = React.lazy(() => import('./AdminDashboard'));
332
- const UserDashboard = React.lazy(() => import('./UserDashboard'));
333
-
334
- function App() {
335
- const { user } = useUnifiedAuth();
336
-
337
- return (
338
- <Suspense fallback={<div>Loading dashboard...</div>}>
339
- {user?.role === 'admin' ? <AdminDashboard /> : <UserDashboard />}
340
- </Suspense>
341
- );
342
- }
343
- ```
344
-
345
- ### 3. Component Lazy Loading
346
-
347
- ```typescript
348
- import { useCan } from '@jmruthers/pace-core/rbac';
349
- import { useUnifiedAuth } from '@jmruthers/pace-core/providers';
350
-
351
- // Lazy load components based on user permissions
352
- function ConditionalComponent({ permission, children }) {
353
- const { user, selectedOrganisationId } = useUnifiedAuth();
354
- const { can, isLoading } = useCan(
355
- user?.id || '',
356
- { organisationId: selectedOrganisationId || '', eventId: undefined, appId: undefined },
357
- permission
358
- );
359
- const [shouldLoad, setShouldLoad] = useState(false);
360
-
361
- useEffect(() => {
362
- if (!isLoading && can) {
363
- setShouldLoad(true);
364
- }
365
- }, [can, isLoading]);
366
-
367
- if (!shouldLoad) return null;
368
-
369
- return <Suspense fallback={<div>Loading...</div>}>{children}</Suspense>;
370
- }
371
-
372
- // Usage
373
- <ConditionalComponent permission="admin:analytics">
374
- <AnalyticsDashboard />
375
- </ConditionalComponent>
376
- ```
377
-
378
- ## Memory Management
379
-
380
- ### 1. Cleanup on Unmount
381
-
382
- ```typescript
383
- import { useEffect, useRef } from 'react';
384
- import { useEvents } from '@jmruthers/pace-core';
385
-
386
- function EventMonitor() {
387
- const { events } = useEvents();
388
- const mountedRef = useRef(true);
389
-
390
- useEffect(() => {
391
- return () => {
392
- mountedRef.current = false;
393
- };
394
- }, []);
395
-
396
- useEffect(() => {
397
- if (!mountedRef.current) return;
398
-
399
- const timer = setInterval(() => {
400
- if (mountedRef.current) {
401
- // Update logic here
402
- console.log('Events updated:', events.length);
403
- }
404
- }, 5000);
405
-
406
- return () => {
407
- clearInterval(timer);
408
- };
409
- }, [events]);
410
-
411
- return <div>Monitoring {events.length} events</div>;
412
- }
413
- ```
414
-
415
- ### 2. Event Listener Cleanup
416
-
417
- ```typescript
418
- import { useEffect } from 'react';
419
- import { useUnifiedAuth } from '@jmruthers/pace-core';
420
-
421
- function AuthListener() {
422
- const { user, signOut } = useUnifiedAuth();
423
-
424
- useEffect(() => {
425
- const handleStorageChange = (e) => {
426
- if (e.key === 'supabase.auth.token' && !e.newValue) {
427
- // Token was removed, sign out
428
- signOut();
429
- }
430
- };
431
-
432
- window.addEventListener('storage', handleStorageChange);
433
- return () => {
434
- window.removeEventListener('storage', handleStorageChange);
435
- };
436
- }, [signOut]);
437
-
438
- return null;
439
- }
440
- ```
441
-
442
- ### 3. Large List Optimization
443
-
444
- ```typescript
445
- import { useVirtualizer } from '@tanstack/react-virtual';
446
- import { useEvents } from '@jmruthers/pace-core';
447
-
448
- function VirtualizedEventList() {
449
- const { events } = useEvents();
450
- const parentRef = useRef();
451
-
452
- const rowVirtualizer = useVirtualizer({
453
- count: events.length,
454
- getScrollElement: () => parentRef.current,
455
- estimateSize: () => 100,
456
- });
457
-
458
- return (
459
- <div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
460
- <div
461
- style={{
462
- height: `${rowVirtualizer.getTotalSize()}px`,
463
- width: '100%',
464
- position: 'relative',
465
- }}
466
- >
467
- {rowVirtualizer.getVirtualItems().map((virtualRow) => {
468
- const event = events[virtualRow.index];
469
- return (
470
- <div
471
- key={event.id}
472
- style={{
473
- position: 'absolute',
474
- top: 0,
475
- left: 0,
476
- width: '100%',
477
- height: `${virtualRow.size}px`,
478
- transform: `translateY(${virtualRow.start}px)`,
479
- }}
480
- >
481
- <EventCard event={event} />
482
- </div>
483
- );
484
- })}
485
- </div>
486
- </div>
487
- );
488
- }
489
- ```
490
-
491
- ## Network Optimization
492
-
493
- ### RBAC Performance Optimizations
494
-
495
- The RBAC system includes built-in performance optimizations that significantly reduce network requests:
496
-
497
- - **Request Deduplication**: Multiple components checking the same permission share network requests
498
- - **Enhanced Caching**: Two-tier caching (60s short-term + 5min session cache)
499
- - **Batched Audit Logging**: Audit events are batched to reduce network requests
500
- - **Memoization**: Components are memoized to prevent unnecessary re-renders
501
-
502
- See the [RBAC Performance Guide](../rbac/performance.md) for detailed information.
503
-
504
- ### 1. Request Deduplication
505
-
506
- ```typescript
507
- import { useMemoizedCallback } from '@jmruthers/pace-core';
508
-
509
- function OptimizedDataFetcher() {
510
- const { supabase } = useSupabase();
511
- const requestCache = useRef(new Map());
512
-
513
- const fetchEventData = useMemoizedCallback(async (eventId) => {
514
- // Check cache first
515
- if (requestCache.current.has(eventId)) {
516
- return requestCache.current.get(eventId);
517
- }
518
-
519
- // Make request
520
- const { data, error } = await supabase
521
- .from('events')
522
- .select('*')
523
- .eq('id', eventId)
524
- .single();
525
-
526
- if (error) throw error;
527
-
528
- // Cache result
529
- requestCache.current.set(eventId, data);
530
- return data;
531
- }, [supabase]);
532
-
533
- return (
534
- <div>
535
- {eventIds.map(id => (
536
- <EventDetails key={id} eventId={id} onFetch={fetchEventData} />
537
- ))}
538
- </div>
539
- );
540
- }
541
- ```
542
-
543
- ### 2. Batch Requests
544
-
545
- ```typescript
546
- import { useSupabase } from '@jmruthers/pace-core';
547
-
548
- function BatchDataFetcher() {
549
- const { supabase } = useSupabase();
550
- const [events, setEvents] = useState([]);
551
- const [loading, setLoading] = useState(false);
552
-
553
- const fetchEventsBatch = async (eventIds) => {
554
- setLoading(true);
555
- try {
556
- const { data, error } = await supabase
557
- .from('events')
558
- .select('*')
559
- .in('id', eventIds);
560
-
561
- if (error) throw error;
562
- setEvents(data);
563
- } catch (error) {
564
- console.error('Failed to fetch events:', error);
565
- } finally {
566
- setLoading(false);
567
- }
568
- };
569
-
570
- return (
571
- <div>
572
- {loading && <div>Loading...</div>}
573
- <EventList events={events} />
574
- </div>
575
- );
576
- }
577
- ```
578
-
579
- ### 3. Progressive Loading
580
-
581
- ```typescript
582
- import { useState, useEffect } from 'react';
583
- import { useEvents } from '@jmruthers/pace-core';
584
-
585
- function ProgressiveEventList() {
586
- const { events } = useEvents();
587
- const [visibleEvents, setVisibleEvents] = useState([]);
588
- const [page, setPage] = useState(1);
589
- const pageSize = 10;
590
-
591
- useEffect(() => {
592
- const start = 0;
593
- const end = page * pageSize;
594
- setVisibleEvents(events.slice(start, end));
595
- }, [events, page]);
596
-
597
- const loadMore = () => {
598
- setPage(prev => prev + 1);
599
- };
600
-
601
- const hasMore = visibleEvents.length < events.length;
602
-
603
- return (
604
- <div>
605
- {visibleEvents.map(event => (
606
- <EventCard key={event.id} event={event} />
607
- ))}
608
- {hasMore && (
609
- <button onClick={loadMore}>
610
- Load More ({events.length - visibleEvents.length} remaining)
611
- </button>
612
- )}
613
- </div>
614
- );
615
- }
616
- ```
617
-
618
- ## Performance Monitoring
619
-
620
- ### 1. Component Performance Tracking
621
-
622
- ```typescript
623
- import { useComponentPerformance } from '@jmruthers/pace-core';
624
-
625
- function PerformanceMonitor() {
626
- const { renderCount, averageRenderTime, lastRenderTime } = useComponentPerformance();
627
-
628
- useEffect(() => {
629
- if (averageRenderTime > 16) { // 60fps threshold
630
- console.warn('Component rendering slowly:', averageRenderTime);
631
- }
632
- }, [averageRenderTime]);
633
-
634
- return (
635
- <div className="performance-monitor">
636
- <div>Renders: {renderCount}</div>
637
- <div>Avg Time: {averageRenderTime.toFixed(2)}ms</div>
638
- <div>Last Render: {lastRenderTime.toFixed(2)}ms</div>
639
- </div>
640
- );
641
- }
642
- ```
643
-
644
- ### 2. Network Performance
645
-
646
- ```typescript
647
- import { useUnifiedAuth } from '@jmruthers/pace-core';
648
-
649
- function NetworkMonitor() {
650
- const { error } = useUnifiedAuth();
651
- const [networkStats, setNetworkStats] = useState({
652
- requests: 0,
653
- errors: 0,
654
- avgResponseTime: 0,
655
- });
656
-
657
- useEffect(() => {
658
- const startTime = performance.now();
659
-
660
- return () => {
661
- const endTime = performance.now();
662
- const responseTime = endTime - startTime;
663
-
664
- setNetworkStats(prev => ({
665
- ...prev,
666
- requests: prev.requests + 1,
667
- avgResponseTime: (prev.avgResponseTime + responseTime) / 2,
668
- }));
669
- };
670
- }, []);
671
-
672
- return (
673
- <div className="network-monitor">
674
- <div>Requests: {networkStats.requests}</div>
675
- <div>Errors: {networkStats.errors}</div>
676
- <div>Avg Response: {networkStats.avgResponseTime.toFixed(2)}ms</div>
677
- </div>
678
- );
679
- }
680
- ```
681
-
682
- ### 3. Memory Usage Monitoring
683
-
684
- ```typescript
685
- function MemoryMonitor() {
686
- const [memoryInfo, setMemoryInfo] = useState(null);
687
-
688
- useEffect(() => {
689
- const updateMemoryInfo = () => {
690
- if ('memory' in performance) {
691
- setMemoryInfo({
692
- used: performance.memory.usedJSHeapSize,
693
- total: performance.memory.totalJSHeapSize,
694
- limit: performance.memory.jsHeapSizeLimit,
695
- });
696
- }
697
- };
698
-
699
- const interval = setInterval(updateMemoryInfo, 5000);
700
- updateMemoryInfo();
701
-
702
- return () => clearInterval(interval);
703
- }, []);
704
-
705
- if (!memoryInfo) return null;
706
-
707
- const usagePercent = (memoryInfo.used / memoryInfo.limit) * 100;
708
-
709
- return (
710
- <div className="memory-monitor">
711
- <div>Memory Usage: {usagePercent.toFixed(1)}%</div>
712
- <div>Used: {(memoryInfo.used / 1024 / 1024).toFixed(1)}MB</div>
713
- <div>Total: {(memoryInfo.total / 1024 / 1024).toFixed(1)}MB</div>
714
- </div>
715
- );
716
- }
717
- ```
718
-
719
- ## Performance Best Practices Checklist
720
-
721
- ### Development Checklist
722
-
723
- - [ ] Use React.memo for expensive components
724
- - [ ] Memoize expensive calculations with useMemo
725
- - [ ] Memoize event handlers with useCallback
726
- - [ ] Implement proper cleanup in useEffect
727
- - [ ] Use lazy loading for large components
728
- - [ ] Implement virtual scrolling for large lists
729
- - [ ] Cache expensive API calls
730
- - [ ] Debounce user input
731
- - [ ] Optimize bundle size with tree shaking
732
- - [ ] Monitor component render performance
733
-
734
- ### Production Checklist
735
-
736
- - [ ] Enable production builds
737
- - [ ] Implement proper error boundaries
738
- - [ ] Set up performance monitoring
739
- - [ ] Optimize images and assets
740
- - [ ] Configure proper caching headers
741
- - [ ] Implement service workers for offline support
742
- - [ ] Monitor Core Web Vitals
743
- - [ ] Set up automated performance testing
744
- - [ ] Configure CDN for static assets
745
- - [ ] Implement progressive loading
746
-
747
- ### Monitoring Checklist
748
-
749
- - [ ] Track component render times
750
- - [ ] Monitor API response times
751
- - [ ] Track memory usage
752
- - [ ] Monitor bundle size
753
- - [ ] Set up performance alerts
754
- - [ ] Track user experience metrics
755
- - [ ] Monitor error rates
756
- - [ ] Track loading times
757
- - [ ] Monitor Core Web Vitals
758
- - [ ] Set up automated performance reports
759
-
760
- ## Performance Tools
761
-
762
- ### 1. React DevTools Profiler
763
-
764
- ```typescript
765
- import { Profiler } from 'react';
766
-
767
- function ProfiledComponent() {
768
- const onRenderCallback = (id, phase, actualDuration) => {
769
- console.log(`Component ${id} took ${actualDuration}ms to ${phase}`);
770
- };
771
-
772
- return (
773
- <Profiler id="EventList" onRender={onRenderCallback}>
774
- <EventList />
775
- </Profiler>
776
- );
777
- }
778
- ```
779
-
780
- ### 2. Custom Performance Hooks
781
-
782
- ```typescript
783
- function usePerformanceMonitor(componentName) {
784
- const renderCount = useRef(0);
785
- const startTime = useRef(performance.now());
786
-
787
- useEffect(() => {
788
- renderCount.current += 1;
789
- const renderTime = performance.now() - startTime.current;
790
-
791
- console.log(`${componentName} rendered in ${renderTime.toFixed(2)}ms`);
792
- startTime.current = performance.now();
793
- });
794
- }
795
- ```
796
-
797
- ### 3. Performance Budgets
798
-
799
- ```typescript
800
- // Set performance budgets
801
- const PERFORMANCE_BUDGETS = {
802
- firstContentfulPaint: 1500, // 1.5s
803
- largestContentfulPaint: 2500, // 2.5s
804
- firstInputDelay: 100, // 100ms
805
- cumulativeLayoutShift: 0.1, // 0.1
806
- };
807
-
808
- function checkPerformanceBudget(metrics) {
809
- Object.entries(PERFORMANCE_BUDGETS).forEach(([metric, budget]) => {
810
- if (metrics[metric] > budget) {
811
- console.warn(`${metric} exceeded budget: ${metrics[metric]} > ${budget}`);
812
- }
813
- });
814
- }
815
- ```
816
-
817
- ## Advanced Performance Techniques
818
-
819
- ### Bundle Optimization
820
-
821
- #### Tree Shaking
822
-
823
- **Goal**: Minimize bundle size by eliminating unused code.
824
-
825
- **Implementation**:
826
- ```typescript
827
- // ✅ Good - Named exports for tree shaking
828
- export { Button } from './Button';
829
- export { Card } from './Card';
830
- export { DataTable } from './DataTable';
831
-
832
- // ❌ Bad - Default exports reduce tree shaking
833
- export default { Button, Card, DataTable };
834
- ```
835
-
836
- **Verify Tree Shaking**:
837
- ```bash
838
- # Check bundle size
839
- npm run build
840
- npx vite-bundle-visualizer
841
- ```
842
-
843
- #### Dynamic Imports
844
-
845
- **Use Case**: Load components only when needed.
846
-
847
- ```tsx
848
- import React, { Suspense, lazy } from 'react';
849
-
850
- // Lazy load heavy components
851
- const DataTable = lazy(() => import('@jmruthers/pace-core').then(m => ({ default: m.DataTable })));
852
- const ChartEditor = lazy(() => import('./components/ChartEditor'));
853
-
854
- function App() {
855
- return (
856
- <Suspense fallback={<LoadingSpinner />}>
857
- <DataTable data={data} columns={columns} />
858
- </Suspense>
859
- );
860
- }
861
- ```
862
-
863
- #### Analysis Tools
864
-
865
- ```bash
866
- # Install analyzer
867
- npm install -D vite-bundle-visualizer
868
-
869
- # Analyze bundle
870
- npx vite-bundle-visualizer dist/stats.html
871
- ```
872
-
873
- ### Advanced Component Memoization
874
-
875
- #### React.memo for Expensive Components
876
-
877
- ```tsx
878
- import React from 'react';
879
- import { Card } from '@jmruthers/pace-core';
880
-
881
- interface UserCardProps {
882
- user: User;
883
- onEdit: (userId: string) => void;
884
- }
885
-
886
- // Memoize expensive components
887
- const UserCard = React.memo(({ user, onEdit }: UserCardProps) => {
888
- return (
889
- <Card className="p-4">
890
- <h3>{user.name}</h3>
891
- <p>{user.email}</p>
892
- <button onClick={() => onEdit(user.id)}>Edit</button>
893
- </Card>
894
- );
895
- });
896
-
897
- // Custom comparison function for complex props
898
- const ComplexComponent = React.memo(
899
- ({ data, config }: { data: any[]; config: any }) => {
900
- return <DataTable data={data} columns={config.columns} />;
901
- },
902
- (prevProps, nextProps) => {
903
- // Only re-render if data length or config changed
904
- return (
905
- prevProps.data.length === nextProps.data.length &&
906
- JSON.stringify(prevProps.config) === JSON.stringify(nextProps.config)
907
- );
908
- }
909
- );
910
- ```
911
-
912
- #### useMemo for Expensive Calculations
913
-
914
- ```tsx
915
- import { useMemo } from 'react';
916
- import { DataTable } from '@jmruthers/pace-core';
917
-
918
- function ExpensiveDataProcessor({ rawData }: { rawData: any[] }) {
919
- // Memoize expensive data processing
920
- const processedData = useMemo(() => {
921
- return rawData.map(item => ({
922
- ...item,
923
- // Expensive calculations
924
- score: calculateComplexScore(item),
925
- category: categorizeItem(item),
926
- processed: true
927
- }));
928
- }, [rawData]);
929
-
930
- // Memoize column configuration
931
- const columns = useMemo(() => [
932
- { accessorKey: 'name', header: 'Name' },
933
- { accessorKey: 'score', header: 'Score' },
934
- { accessorKey: 'category', header: 'Category' }
935
- ], []);
936
-
937
- return <DataTable data={processedData} columns={columns} />;
938
- }
939
- ```
940
-
941
- ### Memory Management
942
-
943
- #### Preventing Memory Leaks
944
-
945
- ```tsx
946
- import { useEffect, useRef } from 'react';
947
-
948
- function DataFetcher() {
949
- const isMountedRef = useRef(true);
950
-
951
- useEffect(() => {
952
- const fetchData = async () => {
953
- try {
954
- const data = await api.getData();
955
- if (isMountedRef.current) {
956
- setData(data);
957
- }
958
- } catch (error) {
959
- if (isMountedRef.current) {
960
- setError(error);
961
- }
962
- }
963
- };
964
-
965
- fetchData();
966
-
967
- return () => {
968
- isMountedRef.current = false;
969
- };
970
- }, []);
971
-
972
- // Cleanup subscriptions
973
- useEffect(() => {
974
- const subscription = eventBus.subscribe('dataUpdate', handleUpdate);
975
-
976
- return () => {
977
- subscription.unsubscribe();
978
- };
979
- }, []);
980
- }
981
- ```
982
-
983
- #### Efficient State Updates
984
-
985
- ```tsx
986
- import { useCallback, useReducer } from 'react';
987
-
988
- // Use reducer for complex state
989
- function dataReducer(state: any, action: any) {
990
- switch (action.type) {
991
- case 'SET_DATA':
992
- return { ...state, data: action.payload };
993
- case 'UPDATE_ITEM':
994
- return {
995
- ...state,
996
- data: state.data.map(item =>
997
- item.id === action.id ? { ...item, ...action.updates } : item
998
- )
999
- };
1000
- case 'DELETE_ITEM':
1001
- return {
1002
- ...state,
1003
- data: state.data.filter(item => item.id !== action.id)
1004
- };
1005
- default:
1006
- return state;
1007
- }
1008
- }
1009
-
1010
- function OptimizedDataManager() {
1011
- const [state, dispatch] = useReducer(dataReducer, { data: [], loading: false });
1012
-
1013
- // Memoize dispatch functions
1014
- const updateItem = useCallback((id: string, updates: any) => {
1015
- dispatch({ type: 'UPDATE_ITEM', id, updates });
1016
- }, []);
1017
-
1018
- const deleteItem = useCallback((id: string) => {
1019
- dispatch({ type: 'DELETE_ITEM', id });
1020
- }, []);
1021
-
1022
- return (
1023
- <DataTable
1024
- data={state.data}
1025
- onUpdate={updateItem}
1026
- onDelete={deleteItem}
1027
- />
1028
- );
1029
- }
1030
- ```
1031
-
1032
- ### Network Optimization
1033
-
1034
- #### Request Deduplication
1035
-
1036
- ```tsx
1037
- import { useMemo } from 'react';
1038
-
1039
- // Deduplicate identical requests
1040
- const requestCache = new Map();
1041
-
1042
- function useOptimizedFetch(url: string, options: any) {
1043
- const cacheKey = useMemo(() =>
1044
- `${url}-${JSON.stringify(options)}`,
1045
- [url, options]
1046
- );
1047
-
1048
- const fetchData = useCallback(async () => {
1049
- if (requestCache.has(cacheKey)) {
1050
- return requestCache.get(cacheKey);
1051
- }
1052
-
1053
- const promise = fetch(url, options).then(res => res.json());
1054
- requestCache.set(cacheKey, promise);
1055
-
1056
- // Clear cache after 5 minutes
1057
- setTimeout(() => {
1058
- requestCache.delete(cacheKey);
1059
- }, 5 * 60 * 1000);
1060
-
1061
- return promise;
1062
- }, [cacheKey]);
1063
-
1064
- return fetchData;
1065
- }
1066
- ```
1067
-
1068
- #### Batch API Calls
1069
-
1070
- ```tsx
1071
- import { useCallback } from 'react';
1072
-
1073
- function useBatchRequests() {
1074
- const batchRequests = useCallback(async (requests: any[]) => {
1075
- // Group requests by endpoint
1076
- const groupedRequests = requests.reduce((groups, request) => {
1077
- const key = request.endpoint;
1078
- if (!groups[key]) groups[key] = [];
1079
- groups[key].push(request);
1080
- return groups;
1081
- }, {});
1082
-
1083
- // Execute batches in parallel
1084
- const results = await Promise.all(
1085
- Object.entries(groupedRequests).map(([endpoint, batch]) =>
1086
- api.batchRequest(endpoint, batch)
1087
- )
1088
- );
1089
-
1090
- return results.flat();
1091
- }, []);
1092
-
1093
- return batchRequests;
1094
- }
1095
- ```
1096
-
1097
- ### Code Splitting Strategies
1098
-
1099
- #### Route-Based Splitting
1100
-
1101
- ```tsx
1102
- import { lazy, Suspense } from 'react';
1103
- import { Routes, Route } from 'react-router-dom';
1104
-
1105
- // Lazy load route components
1106
- const Dashboard = lazy(() => import('./pages/Dashboard'));
1107
- const Users = lazy(() => import('./pages/Users'));
1108
- const Settings = lazy(() => import('./pages/Settings'));
1109
-
1110
- function App() {
1111
- return (
1112
- <Suspense fallback={<LoadingSpinner />}>
1113
- <Routes>
1114
- <Route path="/" element={<Dashboard />} />
1115
- <Route path="/users" element={<Users />} />
1116
- <Route path="/settings" element={<Settings />} />
1117
- </Routes>
1118
- </Suspense>
1119
- );
1120
- }
1121
- ```
1122
-
1123
- #### Feature-Based Splitting
1124
-
1125
- ```tsx
1126
- import { lazy, Suspense } from 'react';
1127
- import { useCan } from '@jmruthers/pace-core';
1128
-
1129
- // Lazy load admin features
1130
- const AdminPanel = lazy(() => import('./AdminPanel'));
1131
- const UserManagement = lazy(() => import('./UserManagement'));
1132
-
1133
- function App() {
1134
- const { hasPermission } = useCan();
1135
-
1136
- return (
1137
- <div>
1138
- <MainContent />
1139
-
1140
- {hasPermission('admin:access') && (
1141
- <Suspense fallback={<div>Loading admin features...</div>}>
1142
- <AdminPanel />
1143
- </Suspense>
1144
- )}
1145
-
1146
- {hasPermission('users:manage') && (
1147
- <Suspense fallback={<div>Loading user management...</div>}>
1148
- <UserManagement />
1149
- </Suspense>
1150
- )}
1151
- </div>
1152
- );
1153
- }
1154
- ```
1155
-
1156
- ### Performance Monitoring
1157
-
1158
- #### Real-Time Performance Tracking
1159
-
1160
- ```tsx
1161
- import { useEffect } from 'react';
1162
-
1163
- function usePerformanceMonitor() {
1164
- useEffect(() => {
1165
- // Monitor Core Web Vitals
1166
- const observer = new PerformanceObserver((list) => {
1167
- for (const entry of list.getEntries()) {
1168
- console.log('Performance metric:', {
1169
- name: entry.name,
1170
- value: entry.value,
1171
- startTime: entry.startTime
1172
- });
1173
- }
1174
- });
1175
-
1176
- observer.observe({ entryTypes: ['measure', 'navigation'] });
1177
-
1178
- return () => observer.disconnect();
1179
- }, []);
1180
- }
1181
-
1182
- // Usage in components
1183
- function MyComponent() {
1184
- usePerformanceMonitor();
1185
-
1186
- return <div>Component content</div>;
1187
- }
1188
- ```
1189
-
1190
- #### Bundle Size Monitoring
1191
-
1192
- ```bash
1193
- # Add to package.json scripts
1194
- {
1195
- "scripts": {
1196
- "analyze": "npm run build && npx vite-bundle-visualizer",
1197
- "size-check": "npm run build && npx bundlesize"
1198
- }
1199
- }
1200
-
1201
- # Monitor bundle size
1202
- npm run analyze
1203
- ```
1204
-
1205
- ### Performance Testing
1206
-
1207
- #### Automated Performance Tests
1208
-
1209
- ```typescript
1210
- // performance.test.ts
1211
- import { render, screen } from '@testing-library/react';
1212
- import { performance } from 'perf_hooks';
1213
-
1214
- describe('Performance Tests', () => {
1215
- test('DataTable renders within performance budget', async () => {
1216
- const start = performance.now();
1217
-
1218
- render(<DataTable data={largeDataset} columns={columns} />);
1219
-
1220
- await screen.findByRole('table');
1221
-
1222
- const end = performance.now();
1223
- const renderTime = end - start;
1224
-
1225
- // Should render within 100ms
1226
- expect(renderTime).toBeLessThan(100);
1227
- });
1228
-
1229
- test('Component re-renders are optimized', () => {
1230
- let renderCount = 0;
1231
-
1232
- const TestComponent = () => {
1233
- renderCount++;
1234
- return <div>Test</div>;
1235
- };
1236
-
1237
- const { rerender } = render(<TestComponent />);
1238
-
1239
- // Re-render with same props
1240
- rerender(<TestComponent />);
1241
-
1242
- // Should not cause unnecessary re-renders
1243
- expect(renderCount).toBe(1);
1244
- });
1245
- });
1246
- ```
1247
-
1248
- ## Performance Checklist
1249
-
1250
- ### Development Phase
1251
- - [ ] Use React.memo for expensive components
1252
- - [ ] Implement useCallback for event handlers
1253
- - [ ] Use useMemo for expensive calculations
1254
- - [ ] Implement proper cleanup in useEffect
1255
- - [ ] Use dynamic imports for large components
1256
- - [ ] Optimize bundle with tree shaking
1257
-
1258
- ### Production Phase
1259
- - [ ] Enable production optimizations
1260
- - [ ] Monitor Core Web Vitals
1261
- - [ ] Implement performance budgets
1262
- - [ ] Set up performance monitoring
1263
- - [ ] Test with real data volumes
1264
- - [ ] Optimize images and assets
1265
-
1266
- ### Monitoring Phase
1267
- - [ ] Track bundle size over time
1268
- - [ ] Monitor render performance
1269
- - [ ] Watch for memory leaks
1270
- - [ ] Analyze user experience metrics
1271
- - [ ] Set up performance alerts
1272
- - [ ] Regular performance audits
1273
-
1274
- ## Related Documentation
1275
-
1276
- - [Data Tables Performance](../implementation-guides/data-tables.md#performance-optimization) - DataTable-specific optimizations
1277
- - [Authentication Performance](../implementation-guides/authentication.md#performance) - Auth-related performance
1278
- - [Best Practices Overview](./README.md) - General best practices
1279
- - [Troubleshooting Performance Issues](../troubleshooting/README.md#performance-issues) - Performance debugging
1280
-
1281
- ## ♿ Accessibility
1282
-
1283
- Performance optimizations should maintain accessibility:
1284
-
1285
- - **Lazy loading doesn't break screen readers** - Ensure lazy-loaded content is accessible
1286
- - **Code splitting maintains keyboard navigation** - Verify keyboard navigation works after code splitting
1287
- - **Memoization doesn't affect focus management** - Ensure focus handling remains correct
1288
- - **Performance optimizations are tested with assistive technologies** - Verify optimizations don't break accessibility
1289
- - **Loading states are announced** - Screen readers should announce performance-related loading states
1290
-
1291
- ### Accessibility Best Practices
1292
-
1293
- 1. **Test optimizations with screen readers** - Verify performance improvements don't break accessibility
1294
- 2. **Ensure keyboard navigation** - All optimized components should remain keyboard accessible
1295
- 3. **Maintain focus visibility** - Focus indicators should remain visible after optimizations
1296
- 4. **Test with assistive technologies** - Verify performance optimizations work with screen readers
1297
- 5. **Balance performance and accessibility** - Don't sacrifice accessibility for performance gains
1298
-
1299
- ## ⚠️ Edge Cases
1300
-
1301
- ### Performance vs Accessibility Trade-offs
1302
-
1303
- When performance optimizations impact accessibility:
1304
- - Find balance between performance and accessibility
1305
- - Test optimizations with assistive technologies
1306
- - Ensure lazy loading doesn't break screen reader navigation
1307
- - Verify code splitting maintains keyboard navigation
1308
- - Document trade-offs when necessary
1309
-
1310
- ### Over-Optimization Issues
1311
-
1312
- When over-optimization causes problems:
1313
- - Monitor for premature optimization
1314
- - Test optimizations in real-world scenarios
1315
- - Profile before and after optimizations
1316
- - Verify optimizations provide measurable benefits
1317
- - Consider maintainability when optimizing
1318
-
1319
- ### Performance Regression
1320
-
1321
- When performance degrades after optimizations:
1322
- - Profile to identify bottlenecks
1323
- - Test with realistic data volumes
1324
- - Monitor performance metrics
1325
- - Rollback optimizations if needed
1326
- - Document performance regression causes
1327
-
1328
- For more information about optimizing your application, see the [Security Guide](./security.md) and [Testing Guide](./testing.md).